第七章 參數的傳遞

Preview:

DESCRIPTION

第七章 參數的傳遞. 陳維魁 博士 wkchen@pchome.com.tw 儒林圖書公司. 大綱. 副程式概念介紹 副程式基本觀念 參數傳遞的方法 別名 超荷法 通用性函數 六種常見的副程式呼叫方式 精選習題. 副程式概念介紹. 副程式的元素 副程式的名稱 參數 實際參數 (actual parameter) 呼叫副程式的參數串列即稱為實際參數,又稱為真實參數。 型式參數 (formal parameter) 被呼叫副程式的參數串列即稱為型式參數,又稱為虛擬參數 (dummy parameter). 副程式概念介紹. 副程式的元素 - PowerPoint PPT Presentation

Citation preview

1

第七章 參數的傳遞 陳維魁 博士wkchen@pchome.com.tw儒林圖書公司

2

大綱 副程式概念介紹 副程式基本觀念 參數傳遞的方法 別名 超荷法 通用性函數 六種常見的副程式呼叫方式 精選習題

3

副程式概念介紹 副程式的元素

副程式的名稱 參數

實際參數 (actual parameter) 呼叫副程式的參數串列即稱為實際參數,又稱為真實參數。

型式參數 (formal parameter) 被呼叫副程式的參數串列即稱為型式參數,又稱為虛擬參數 (dummy parameter)

4

副程式概念介紹 副程式的元素

環境 (environment) 由副程式執行時所參考的全域變數 (global

variable) ,區域變數 (local variable) 及其他必要的資訊構成 副程式執行的程式段

5

範例 program demo;

vara1,a2 : integer;.... procedure swap(b1, b2:integer); var     temp: integer; begin     temp := b1;     b1 := b2;     b2 := temp end;begin    swap(a1, a2)end.

左例中swap(a1,a2)的參數串列(a1,a2) 即為實際參數串列,副程式swap(b1,b2)中的參數串列 (b1,b2) 則為型式參數串列

6

型式參數的語意模型 型式參數的三種不同語意模型分別為

in mode 型式參數可從對應的實際參數接收訊息。

out mode 型式參數可將訊息傳給對應的實際參數

in out mode 型式參數可從對應的實際參數接收訊息也可將訊息傳給對應的實際參數

7

實際與型式參數的對應關係 關鍵字對應法

參數的個數較多時適用 當參數的數目很多時,採用關鍵字對應法,程式的可讀性較高、較易維護不易出錯且可以不必按照特定順序

位置對應法 參數的個數較少時適用 ( 通常是 5 個以下 )

範例 ADA 程式語言呼叫時 Procedure DRAW_AXES(X_ORI,Y_ORI,………) 呼叫方式 1. 位置對應法 DRAW_AXES(500,500,……)

2. 關鍵字對應法 DRAW_AXES(X_ORI=>500, Y_ORI=>500,…..)

8

9

副程式的執行模式 副程式的執行動作是因為呼叫程式呼叫了副程式所引起 當呼叫程式呼叫副程式時會將程式的控制流程轉移到副程式開始處 待副程式執行結束時會將程式的控制流程轉移到呼叫程式中呼叫副程式敘述的下一個敘述 副程式執行時可改變其所處的環境的狀態

10

副程式的執行模式 呼叫程式執行 呼叫 sub( ) 副程式 控制流程轉移到 sub( )副程式sub( ) 副程式執行sub( ) 副程式執行完畢,控制流程轉移回呼叫程式 呼叫程式繼續執行

call sub( )

1

2

65

4

3sub( )

*

呼叫程式 被呼叫程式

11

副程式的種類 程序 (procedure)

沒有傳回值 函式 (function)

函式與程序類似,最大的不同之處是函式會傳回一個值 函式本身亦具有型態 函式也可作為運算式的一部分

12

求最大公因數 程式段 Pascal function gcd(a, b: integer):integer;

begin if b = 0 then gcd := a else gcd := gcd(b, a mod b)end;

13

求最大公因數 程式段 C

int gcd(a, b)int a, b;{ if (b = = 0) return (a); else return (gcd(b, a%b));}

14

參數傳遞的方法 常見參數傳遞的方法

傳值呼叫法 傳址呼叫法 傳名呼叫法 數值結果呼叫法 本文呼叫法

15

傳值呼叫法 (call by value) 呼叫程式呼叫被呼叫程式時,將呼叫程式中實際參數的值,傳給被呼叫程式中對應的型式參數 實際參數與相對應的型式參數不會佔用相同的記憶體空間 沒有副作用 (side effect)- 邊際效應 只提供 in mode 參數

16

傳值呼叫法 (call by value) 優點

實際參數的值只能被讀取,在副程式執行的過程中不會因為更改型式參數的值連帶地將實際參數的值更改 缺點

需配置額外的記憶體空間給型式參數使用

17

傳址呼叫法 (call by address) ( 傳參 ) 又稱為 call by reference 或 call by location 呼叫程式呼叫被呼叫程式時,將呼叫程式中實際參數的位址,傳給被呼叫程式中對應的型式參數 實際參數與對應的型式參數會佔用相同的記憶體空間 有副效應 - 邊際效應 提供 in out mode 參數

18

傳址呼叫法 (call by address) 優點

不需配置額外的記憶體空間給型式參數使用 缺點

在副程式執行的過程中會因為更改型式參數的值連帶地將實際參數的值更改 ( 副作用 )

19

傳名呼叫法 (call by name) 呼叫程式呼叫被呼叫程式時,將呼叫程式中實際參數的名稱,傳給被呼叫程式中對應的型式參數 將副程式中所有型式參數的名稱以實際參數的名稱來替代 實際參數與對應的型式參數會佔用相同的記憶體空間

20

傳名呼叫法 (call by name) 優點

具有較大的彈性,可提供不同型式的實際參數讓同一個副程式做不同的工作 當實際參數為簡單變數時,傳名呼叫法之處理方式與傳址呼叫法相同 當實際參數為常數時,傳名呼叫法之處理方式與傳值呼叫法類似

缺點 程式難讀、不易製作、執行速度較慢及不易學習

21

數值結果呼叫法 (call by value result) 呼叫程式呼叫被呼叫程式時,將呼叫程式中實際參數的值,傳給被呼叫程式中對應的型式參數 實際參數與型式參數不會佔用相同的記憶體位置 當被呼叫程式執行完畢時,會將被呼叫程式中型式參數的值,傳回給呼叫程式中對應的實際參數 提供 in out mode 參數

22

範例 設有一程式語言的副程式如下: 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 同位址參數放同位置,每個都列出來

23

1X=X+Y

2

3

X

Y

C 註 (1)

3Return (X+X+Y)

2

3

X

Y

C 註 (2)

3+3+2=8

∴ 結果為 8

24

範例 若右例以:(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+1 A 值為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

25

(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=2

Z:=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

26

27

本文呼叫法 (call by text) 在呼叫時不把實際參數閉合 (closure) ,而是一直延遲到遇到型式參數時再予閉合 用被呼叫程序環境閉合時的狀態計算實際參數之值

“閉合”是指一程序與其相關環境繫結在一起之過程 LISP 之 FEXPR版本採用此法 和傳名呼叫類似,但是名稱相同時候先用區域參用環境的變數結合,沒有定義的話才會與實際參數結合

28

本文呼叫法範例 var x : integer;

procedure text(y); var x : integer; begin x := 5; writeln(y); end;

begin x:=4; text(x);end.

本文呼叫法處理結果為 5 傳名呼叫法處理則結果為 4 名稱相同時候先用區域參用環境的變數結合,沒有定義的話才會與實際參數結合

29

別名 (aliasing) 兩個或兩個以上名稱不同的變數,佔用相同的記憶體空間 別名形成的原因

參數傳遞時採用傳址呼叫法 變異記錄 (variant record) 指標 Fortran 的“ equivalence” 敘述

30

別名 現象對程式執行結果的影響 已知某一算術運算式 (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)+A 2*3+6=12 由右至左 A×FUN(A)+A 6*3+2=20 先導入 A 值 2*3+2=8 先執行副程式 6*3+6=24 如果沒有邊際效應則運算都是 2*3+2=8

31

32

超荷法 (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

33

C++ Double min (double A, double B) { return (A<B)? A:B; } Int min (int C, int D) { return (C<D)? C:D; } 型態不同時候,使用的函數也不同

34

35

通用性函數 (generic function) 允許參數傳遞的對象為“型態” 主要的用途是可排除程序對資料型態的依賴性 優點

可減少程式碼的長度 可減少撰寫程式時,發生錯誤的可能性

代表性的語言是 ADA 型態改變時候,可以根據傳遞型態,同個函數可以根據參數,處理不同型態

36

ADA 通用性函數範例 generic

type 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) is temp : T; begin temp := A; A := B; B := temp; end;end P;

37

ADA 通用性函數範例 procedure SWAPINT is new SWAP (integer); procedure SWAPINT(A,B:in out integer) is   temp : integer;

begin       temp:=A;A:=B;B:=temp;end;

38

ADA 通用性函數範例 procedure SWAPINT is new SWAP (real); procedure SWAPINT(A,B:in out real) is   temp : real;

begin       temp:=A;A:=B;B:=temp;end;

39

六種常見的副程式呼叫方式 呼叫∕返回副程式 (call∕return subroutine) 遞迴副程式 (recursive subroutine) 例外處理副程式 (exception handling

subroutine) 並行常式 (coroutine) 排程副程式 (scheduled subroutine) 並行程序 (concurrent subroutine)

40

呼叫∕返回副程式 與一般的副程式呼叫是相同的 傳統的呼叫 /返回副程式須滿足以下五項限制

不允許遞迴呼叫 副程式被呼叫時,必須有明顯的呼叫敘述 副程式被呼叫時,應從頭開始執行 副程式被呼叫時,控制流程應立即轉移 單一執行順序

41

遞迴副程式 若副程式可以呼叫本身或透過其他的副程式來呼叫本身 直接遞迴

副程式可以自己呼叫自己 間接遞迴

副程式可以透過其他的副程式來呼叫自己

42

例外處理副程式 處理例外情況的副程式 首創例外處理的語言為 PL/1

43

並行常式 一種交換關係 假設有二個程序分別是 P

與 Q ,其中程序 P 可以啟動 Q 的執行,而程序 Q 也可以啟動程序 P 的執行

當程序啟動另一程序的執行時,會先將自己目前的狀態儲存起來,下次被啟動執行時,會由上次執行結束之處繼續往下執行,而非從頭開始執行

resume Q

Process P

(1)

(5)

resume P

Process Q

(3)

(2)

(4)

44

排程副程式 一般的副程式呼叫是在被呼叫時,立即執行副程式 排程副程式在被呼叫時,並未立即被執行而是須在符合某種條件下才會被啟動執行 範例

CALL SUB AT TIME=100 代表當時間為 100 時,副程式 SUB才會被啟動。

CALL SUB1 AFTER SUB2 代表當副程式 SUB2 執行完畢後,副程式 SUB1才會被啟動

45

並行程序 同時執行的程式段即稱為並行程序

練習 傳名呼叫法、傳值呼叫法及傳址呼叫法在資訊定址值方面有早晚之分,試列出早晚的順序。

46

Ans 資訊定址值方面之速度以傳址呼叫法最快、傳名呼叫法次之而傳值呼叫法則是最慢。

47

練習 假設我們要得到下列控制結構 (control

structure) 則必須分別從單純的呼叫 /回歸(simple call-return) 方式中放鬆那些限制?

(1) 遞迴程序 (recursive procedure) (2) 互動程序 (coroutine) (3) 排程化的副程式 (scheduled

subprogram) (4) 平行的副程式 (concurrent

subprogram)

48

Ans (1) 不允許遞迴呼叫。 (2) 副程式被呼叫時,應從頭開始執行。 (3) 副程式被呼叫時,控制流程應立即轉移。 (4) 單一執行順序。

49

練習 請就以下不同的實際參數對傳值呼叫法及傳址呼叫法的效果為何? (1) 簡單變數 (Simple variable) 。 (2) 常數 (Constant) 。 (3) 運算式 (Expression) 。 (4) 指數為常數的陣列元素。 (5) 指數為運算式的陣列元素。 (6) 陣列。

50

Ans  傳值呼叫 傳址呼叫

簡單變數 傳此簡單變數之值 傳此簡單變數之位址常  數 傳此常數之值 配置一個記憶體空間給此常數,傳該記憶體空間之位址

運 算 式計算運算式之值,傳此值 計算運算式之值,配置一個記憶體空間給此值,傳該記憶體空間之位址

指數為常數的陣列元素求得陣列元素之值,傳此值 求得陣列元素之位址,傳此位址

指數為運算式的陣列元素求得陣列元素之值,傳此值 求得陣列元素之位址,傳此位址

陣  列 通常不允許 傳陣引之起始位址51

練習 試問在 Java 語言中,函數之間的參數如何傳遞?

52

Ans (1) 傳值呼叫法 (call by value) :若參數之型態若為語言本身所提供的資料型態,則採用傳值呼叫法來處理參數傳遞之問題。 (2) 傳址呼叫法 (call by reference) :若參數為物件、陣列等型態,則可提供傳址呼叫法之效果來處理參數傳遞之問題。

53

練習 定義 N!=N*(N-1)*(N-2)*… *2*1例如 5!=5*4*3*2*1=120 (1) 請利用 Recursion 的方式寫出一程

式 PA 來計算 N! (2) 請利用迴圈 (Loop structure) 的方式改寫 PA立另一程式為 PB (3) 比較 PA 和 PB兩程式的執行效率為何?

54

Ans (1) int PA(int N)

{ if (N = = 1) return(1); else return (N*PA(N-1));}

(2) PB:f=1;for (I=2; I<=N; I++) f = f * I;

(3) PB 效率較佳,因為採用非遞迴方式處理程式段。55

練習 以下仿 C 語言語法之主、副程式而言: ( 一 ) 如果所有的參數都是採用傳值呼叫法,寫出執行後所印製之結果並說明其理由。 ( 二 ) 如果所有的參數都是採用傳址呼叫法,寫出執行後所印製之結果並說明其理由。 /* main program */ /* subprogram */

mainO swap(a, b:integer){int i,j; {int temp;i=3; j=5 temp=a;Swap(3,j); a=b;Printf("%d,"3*i+j); b=temp;} }

56

Ans 採用“ call by value” :

輸出結果為 3× i + j=3× 3+5=14 。 採用“ call by reference” : 3× i + j=3× 3+3=12

57

i 3j 5a 3b 5

i 3j 5a 5b 3

i 3j , b 5

a 3

i 3j , b 3

a 5

練習 考慮底下以類似 Pascal 語言語法所定義的二函數副程式: function A(I,K : integer) : integer;

begin     if I=0 then        A : =1     Else        A : = K end;

function B(X: integer) : integer ; begin     B : = A(X, X * B(X-1)) end;

試以傳值呼叫法方式來計算 B(5) 的結果。58

Ans B = 5*B(4)

=5*4*B(3)=5*4*3*B(2)=

5*4*3*2*B(1)=5*4*3*2*1*B(0)= 5*4*3*2*1*1 (∵ B(0)=1)所以,結果為 120

59

練習 就執行下列仿語言語法之程式,舉出兩種可能印出的答案,並提出合理的語意說明。 int fun(int *k)

{*k + = 2; return 2*(*k) +1;}void main( ){int i = 10, dat;dat = fun(&i) + i; printf(“%d”, dat); }

60

Ans 由於副作用之影響,若“ dat=fun(&i)

+i;” 敘述採用左結合性求值,則結果為37;但若“ dat=fun(&i)+i;” 敘述採用右結合性求值,則結果為 31 。

61

練習 以下Pascal程式倘若有參數傳遞 (1) 採數值結果呼叫法則結果為何? (2) 採引用呼叫法則結果為何? program param(input, output);

var a, b :integer;

procedure p(x, y: integer);begin x := x+2; a := x× y; x := x+1;end;

begin a:=1; b:=2; p(a, b); writeln(a);end.

62

Ans 數值結果呼叫法: a. 須額外配置記憶體空間給副程式中之型式參數。 b. 副程式執行完後,將副程式之型式參數串列結果值傳回給對應的主程式實際參數。其作法如下:

引用呼叫法:

63

1

2

1

2

a

b

x

y

1

2

3

2

a

b

x

y

x : = x + 2

6

2

3

2

a

b

x

y

a : = x * y

6

2

4

2

a

b

x

y

a : = x + 1

4

a

2

b

¡D

¡D

x y

(

( )

) writeln(a)2 結果為 4

1

2

y,a x : = x + 2

y,b

3

2

y,a

y,b

a : = x * y 6

2

y,a

y,b

x : = x + 1 7

2

y,a

y,b

writeln(a)7 結果為 7

練習 執行下列的程式,寫出結果。 program House(output);

var thing : integer;procedure Cheat(var hee, haw : integer);begin hee := -1; haw := -hee;end;begin thing := 1; Cheat(thing, thing); writeln(thing);end.

Pascal 程式,由於 Subroutine中,型式參數以“ var”宣告故採用傳址呼叫法。

64

Ans 結果為 1

65

haw, hee, thing 1hee=-1

-1haw=-hee

1writeln(thing)

1

練習 考慮以下程式片段: void main() {

int value=2,list=5; swap(value,list);}void swap(int a, int b){ int temp; temp=a; b=temp;}

(1) 若參數傳遞為以值傳遞,則在 main() 執行完swap(value,list) 之後,變數 value , list 之值各為多少?

(2) 若參數傳遞為以址傳遞,則在 main() 執行完swap(value,list) 之後,變數 value , list 之值各為多少?

66

ANS 採用 call by value 法,作法如下:所以,執行完 swap(value,list) 後, value=2 , list=5 。

採用 call by address 法,作法如下:所以,執行完 swap(value,list) 後, value=2 , list=2 。

67

練習 有一程式如下: program parms(output);

Var i, j : integer;a : array[1..4] of integer;procedure P(x, y : integer);begin i:=i+1; j:=j+1; writeln(x, y); x:=x+1; y:=y+1end;begin for i:=1 to 4 do a 〔 i 〕 := i; i:=1; j:=2; P(a[j], a[i]); writeln(i, j, a[1], a[2], a[3], a[4])end

請問以 (1)Call by reference (2)Call by value (3)Call by name 法傳遞參數,程式執行結果為何?

68

Ans (1) call by reference :傳址

21232334

(2) call by value :21231234

(3) call by name :傳名32231344

69

練習 假設有一 ALGOL-LIKE 程式片段如下,請依以下所列之各種參數傳遞方式分別寫出此程式片段之執行結果。 (1) Call by value (2) Call by address (3) Call by name (4) Call by value-result program Parm(output);

var x: integer;

procedure sub(exp, I : integer)begin I := exp; I := exp;end;begin /* main program */ x := 3; sub(2*x, x); print(x);end.

70

Ans (1) Call by value : ∴結果為 3

(2) Call by address : ∴結果為 6

71

3

6

I, x

exp

I:=exp

6exp

I:=exp

6exp

print (x)6

I, x I, x6 6

Ans 3) Call by name : a. 名稱對應關係: exp=>2*x, I=>x b. 名稱替換: I:=exp=>x:=2*x, I:=exp=>x:=2*x c. 執行: ∴結果為 12 (4) Call by value-result :

∴結果為 6

72

練習 對應參數的位址方法,若以應用於下列程式片段,試問值為何?

Main real L,M,N L = 5 M = 2 N = S(L,2L,L+2M) Output N End(Main)S:sub(X,Y,Z)real X,Y,Z,WY = ZW = Y+Zreturn(W)end(sub)

73

Ans

74

5

2

X, L

M

Y

Y=Z

10

9Z

5

2

X, L

M

Y

W=Y+Z

9

9Z

5

2

X, L

M

Y 9

9Z

18W

return (W)N 18

Recommended