740 likes | 941 Views
第七章 參數的傳遞. 陳維魁 博士 wkchen@pchome.com.tw 儒林圖書公司. 大綱. 副程式概念介紹 副程式基本觀念 參數傳遞的方法 別名 超荷法 通用性函數 六種常見的副程式呼叫方式 精選習題. 副程式概念介紹. 副程式的元素 副程式的名稱 參數 實際參數 (actual parameter) 呼叫副程式的參數串列即稱為實際參數,又稱為真實參數。 型式參數 (formal parameter) 被呼叫副程式的參數串列即稱為型式參數,又稱為虛擬參數 (dummy parameter). 副程式概念介紹. 副程式的元素
E N D
第七章 參數的傳遞 陳維魁 博士 wkchen@pchome.com.tw 儒林圖書公司
大綱 • 副程式概念介紹 • 副程式基本觀念 • 參數傳遞的方法 • 別名 • 超荷法 • 通用性函數 • 六種常見的副程式呼叫方式 • 精選習題
副程式概念介紹 • 副程式的元素 • 副程式的名稱 • 參數 • 實際參數(actual parameter) • 呼叫副程式的參數串列即稱為實際參數,又稱為真實參數。 • 型式參數(formal parameter) • 被呼叫副程式的參數串列即稱為型式參數,又稱為虛擬參數(dummy parameter)
副程式概念介紹 • 副程式的元素 • 環境(environment) • 由副程式執行時所參考的全域變數(global variable),區域變數(local variable)及其他必要的資訊構成 • 副程式執行的程式段
program demo;vara1,a2 : integer;....procedure swap(b1, b2:integer); vartemp: integer; begintemp := b1;b1 := b2;b2 := temp end;beginswap(a1, a2)end. 左例中swap(a1,a2)的參數串列(a1,a2)即為實際參數串列,副程式swap(b1,b2)中的參數串列(b1,b2)則為型式參數串列 範例
型式參數的語意模型 • 型式參數的三種不同語意模型分別為 • in mode • 型式參數可從對應的實際參數接收訊息。 • out mode • 型式參數可將訊息傳給對應的實際參數 • in out mode • 型式參數可從對應的實際參數接收訊息也可將訊息傳給對應的實際參數
實際與型式參數的對應關係 • 關鍵字對應法 • 參數的個數較多時適用 • 當參數的數目很多時,採用關鍵字對應法,程式的可讀性較高、較易維護不易出錯且可以不必按照特定順序 • 位置對應法 • 參數的個數較少時適用(通常是5個以下)
範例 • ADA程式語言呼叫時 • Procedure DRAW_AXES(X_ORI,Y_ORI,………) • 呼叫方式 • 1. 位置對應法 • DRAW_AXES(500,500,……) • 2. 關鍵字對應法 • DRAW_AXES(X_ORI=>500, Y_ORI=>500,…..)
副程式的執行模式 • 副程式的執行動作是因為呼叫程式呼叫了副程式所引起 • 當呼叫程式呼叫副程式時會將程式的控制流程轉移到副程式開始處 • 待副程式執行結束時會將程式的控制流程轉移到呼叫程式中呼叫副程式敘述的下一個敘述 • 副程式執行時可改變其所處的環境的狀態
副程式的執行模式 呼叫程式執行 呼叫sub( )副程式 控制流程轉移到sub( )副程式 sub( )副程式執行 sub( )副程式執行完畢,控制流程轉移回呼叫程式 呼叫程式繼續執行
副程式的種類 • 程序(procedure) • 沒有傳回值 • 函式(function) • 函式與程序類似,最大的不同之處是函式會傳回一個值 • 函式本身亦具有型態 • 函式也可作為運算式的一部分
Pascal function gcd(a, b: integer):integer;begin if b = 0 then gcd := a else gcd := gcd(b, a mod b)end; 求最大公因數 程式段
求最大公因數 程式段 • Cint gcd(a, b)int a, b;{ if (b = = 0) return (a); else return (gcd(b, a%b));}
參數傳遞的方法 • 常見參數傳遞的方法 • 傳值呼叫法 • 傳址呼叫法 • 傳名呼叫法 • 數值結果呼叫法 • 本文呼叫法
傳值呼叫法 (call by value) • 呼叫程式呼叫被呼叫程式時,將呼叫程式中實際參數的值,傳給被呼叫程式中對應的型式參數 • 實際參數與相對應的型式參數不會佔用相同的記憶體空間 • 沒有副作用(side effect)-邊際效應 • 只提供 in mode 參數
傳值呼叫法 (call by value) • 優點 • 實際參數的值只能被讀取,在副程式執行的過程中不會因為更改型式參數的值連帶地將實際參數的值更改 • 缺點 • 需配置額外的記憶體空間給型式參數使用
傳址呼叫法 (call by address) (傳參) • 又稱為call by reference或call by location • 呼叫程式呼叫被呼叫程式時,將呼叫程式中實際參數的位址,傳給被呼叫程式中對應的型式參數 • 實際參數與對應的型式參數會佔用相同的記憶體空間 • 有副效應-邊際效應 • 提供 in out mode 參數
傳址呼叫法 (call by address) • 優點 • 不需配置額外的記憶體空間給型式參數使用 • 缺點 • 在副程式執行的過程中會因為更改型式參數的值連帶地將實際參數的值更改(副作用)
傳名呼叫法 (call by name) • 呼叫程式呼叫被呼叫程式時,將呼叫程式中實際參數的名稱,傳給被呼叫程式中對應的型式參數 • 將副程式中所有型式參數的名稱以實際參數的名稱來替代 • 實際參數與對應的型式參數會佔用相同的記憶體空間
傳名呼叫法 (call by name) • 優點 • 具有較大的彈性,可提供不同型式的實際參數讓同一個副程式做不同的工作 • 當實際參數為簡單變數時,傳名呼叫法之處理方式與傳址呼叫法相同 • 當實際參數為常數時,傳名呼叫法之處理方式與傳值呼叫法類似 • 缺點 • 程式難讀、不易製作、執行速度較慢及不易學習
數值結果呼叫法 (call by value result) • 呼叫程式呼叫被呼叫程式時,將呼叫程式中實際參數的值,傳給被呼叫程式中對應的型式參數 • 實際參數與型式參數不會佔用相同的記憶體位置 • 當被呼叫程式執行完畢時,會將被呼叫程式中型式參數的值,傳回給呼叫程式中對應的實際參數 • 提供 in out mode 參數
設有一程式語言的副程式如下: PROCEDURE P(A,B,C); B=C; RETURN(A+C);END; 若X=1,Y=2,試問執行"R←P(X,X,X+Y)"之後對於 (a)傳名呼叫法 (b)傳值呼叫法 (c)傳址呼叫法三種不同的參數傳送的方式,R之值各為若干? 範例
Ans • (a) 傳名呼叫:8 • 佔用相同的憶體空間。副程式中的參數及指令中的變數都用主程式的參數取代。 • PROCEDURE P(X,X,X+Y); 把名稱替換掉並且計算 B=C; -> X=X+Y=3 RETURN(A+C); -> A+C=>X+X+Y=3+3+2=8END; • (b) 傳值呼叫:4 • X=1,Y=2 P(X,X,X+Y) • A=1 C=3 傳回1+3=4 • (c) 傳址呼叫:6 同位址參數放同位置,每個都列出來
若右例以: (a)傳名呼叫法 (b)傳值呼叫法 (c)傳址呼叫法 (d)數值結果呼叫法 四種不同的引數傳送的方式,A之值各為若干? procedure P(X,Y,Z); begin Y:=Y+1; Z:=X+X; end; begin A:=1; B:=1; P(A+B,A,A); print A; end. 範例
Ans • (a)傳名呼叫法 • A:=1;B:=1;P(A+B,A,A);執行函數 • Y:=Y+1; 以參數換掉A:=A+1A值為2 Z:=X+X; A:=A+B+A+B=6 A值為6 • (b)傳值呼叫法 所有參數分開看 • A:=1;B:=1;P(A+B,A,A);執行P(2,1,1) 此時X=2, y=1 ,z=1 • Y:=Y+1 =2 • Z:=X+X=4 • 此時A還是1
(c)傳址呼叫法 • A:=1; B:=1;P(A+B,A,A); 執行P(X,Y,Z) 此時X=2, Y=Z=A=1同位址 • Y:=Y+1; 此時Y=Z=A=2Z:=X+X; 此時Y=Z=A=2+2 • 數值結果呼叫法 • 將值傳到函數執行 P(2,1,1) 此時X=2, y=1 ,z=1 • 執行Y:=Y+1 =2 • Z:=X+X=4 • 傳回(2,2,4)=>P(A+B,A,A) • A如果取第二個是2,取第三個是4
本文呼叫法 (call by text) • 在呼叫時不把實際參數閉合(closure),而是一直延遲到遇到型式參數時再予閉合 • 用被呼叫程序環境閉合時的狀態計算實際參數之值 • “閉合”是指一程序與其相關環境繫結在一起之過程 • LISP之FEXPR版本採用此法 • 和傳名呼叫類似,但是名稱相同時候先用區域參用環境的變數結合,沒有定義的話才會與實際參數結合
var x : integer;procedure text(y); var x : integer; begin x := 5; writeln(y); end;begin x:=4; text(x);end. 本文呼叫法處理結果為 5 傳名呼叫法處理則結果為 4 名稱相同時候先用區域參用環境的變數結合,沒有定義的話才會與實際參數結合 本文呼叫法範例
別名 (aliasing) • 兩個或兩個以上名稱不同的變數,佔用相同的記憶體空間 • 別名形成的原因 • 參數傳遞時採用傳址呼叫法 • 變異記錄(variant record) • 指標 • Fortran的“equivalence”敘述
別名 現象對程式執行結果的影響 • 已知某一算術運算式(arithmetic expression):A×FUN(A)+A 若執行此運算式前之A值為2,FUN(A)傳回值為3,而執行此運算式時由於副作用(Side effect)造成A值變成6,則下列何者不可能是此運算式執行後之值? (A) 20 (B) 24 (C) 12 (D) 10
由左至右A×FUN(A)+A2*3+6=12 • 由右至左A×FUN(A)+A6*3+2=20 • 先導入A值 2*3+2=8 • 先執行副程式 6*3+6=24 • 如果沒有邊際效應則運算都是2*3+2=8
超荷法 (overloading) • 如果結構(constructure),因為引數的型態不同而具有不同的意義的話,則稱此現象為超荷法 • 範例 • A+B • 若A,B為整數則執行整數加法運算;若A,B為實數則執行實數加法運算
Algol68中關於ABS()函數 有三種定義 • Abs=(real A) real: if A<0 then –A else A fi • ABS=(int B) int: if B<0 then –B else B fi • ABS=(long real C) long real: if C<0 then –C else C fi
C++ • Double min (double A, double B) • { • return (A<B)? A:B; • } • Int min (int C, int D) • { • return (C<D)? C:D; • } • 型態不同時候,使用的函數也不同
通用性函數 (generic function) • 允許參數傳遞的對象為“型態” • 主要的用途是可排除程序對資料型態的依賴性 • 優點 • 可減少程式碼的長度 • 可減少撰寫程式時,發生錯誤的可能性 • 代表性的語言是ADA • 型態改變時候,可以根據傳遞型態,同個函數可以根據參數,處理不同型態
ADA 通用性函數範例 • generictype T is private;package P is procedure SWAP (A, B: in out T);end P;package body P is procedure SWAP (A, B: in out T) istemp : T; begin temp := A; A := B; B := temp; end;end P;
ADA 通用性函數範例 • procedure SWAPINT is new SWAP (integer); procedure SWAPINT(A,B:in out integer) istemp : integer; begintemp:=A;A:=B;B:=temp;end;
ADA 通用性函數範例 • procedure SWAPINT is new SWAP (real); procedure SWAPINT(A,B:in out real) istemp : real; begintemp:=A;A:=B;B:=temp;end;
六種常見的副程式呼叫方式 • 呼叫∕返回副程式(call∕return subroutine) • 遞迴副程式(recursive subroutine) • 例外處理副程式(exception handling subroutine) • 並行常式(coroutine) • 排程副程式(scheduled subroutine) • 並行程序(concurrent subroutine)
呼叫∕返回副程式 • 與一般的副程式呼叫是相同的 • 傳統的呼叫/返回副程式須滿足以下五項限制 • 不允許遞迴呼叫 • 副程式被呼叫時,必須有明顯的呼叫敘述 • 副程式被呼叫時,應從頭開始執行 • 副程式被呼叫時,控制流程應立即轉移 • 單一執行順序
遞迴副程式 • 若副程式可以呼叫本身或透過其他的副程式來呼叫本身 • 直接遞迴 • 副程式可以自己呼叫自己 • 間接遞迴 • 副程式可以透過其他的副程式來呼叫自己
例外處理副程式 • 處理例外情況的副程式 • 首創例外處理的語言為 PL/1
一種交換關係 假設有二個程序分別是P與Q,其中程序P可以啟動Q的執行,而程序Q也可以啟動程序P的執行 當程序啟動另一程序的執行時,會先將自己目前的狀態儲存起來,下次被啟動執行時,會由上次執行結束之處繼續往下執行,而非從頭開始執行 並行常式
排程副程式 • 一般的副程式呼叫是在被呼叫時,立即執行副程式 • 排程副程式在被呼叫時,並未立即被執行而是須在符合某種條件下才會被啟動執行 • 範例 • CALL SUB AT TIME=100 • 代表當時間為100時,副程式SUB才會被啟動。 • CALL SUB1 AFTER SUB2 • 代表當副程式SUB2執行完畢後,副程式SUB1才會被啟動
並行程序 • 同時執行的程式段即稱為並行程序
練習 • 傳名呼叫法、傳值呼叫法及傳址呼叫法在資訊定址值方面有早晚之分,試列出早晚的順序。
Ans • 資訊定址值方面之速度以傳址呼叫法最快、傳名呼叫法次之而傳值呼叫法則是最慢。
練習 • 假設我們要得到下列控制結構(control structure)則必須分別從單純的呼叫/回歸(simple call-return)方式中放鬆那些限制? • (1) 遞迴程序(recursive procedure) • (2) 互動程序(coroutine) • (3) 排程化的副程式(scheduled subprogram) • (4) 平行的副程式(concurrent subprogram)
Ans • (1) 不允許遞迴呼叫。 • (2) 副程式被呼叫時,應從頭開始執行。 • (3) 副程式被呼叫時,控制流程應立即轉移。 • (4) 單一執行順序。
練習 • 請就以下不同的實際參數對傳值呼叫法及傳址呼叫法的效果為何? • (1) 簡單變數(Simple variable)。 • (2) 常數(Constant)。 • (3) 運算式(Expression)。 • (4) 指數為常數的陣列元素。 • (5) 指數為運算式的陣列元素。 • (6) 陣列。