第八章 自訂副程式 8-1 程序 8-2 函式 8-3 參數列 8-4 遞迴 8-5 多載(Overloading)
8-1 程序 程序(Procedure)的語法如下,其中程序名稱的命名規則同2-1節的識別字命名規則,參數的詳細說明,請看8-3節。 8-1 程序 程序(Procedure)的語法如下,其中程序名稱的命名規則同2-1節的識別字命名規則,參數的詳細說明,請看8-3節。 procedure程序名稱(參數列); 區域變數宣告 begin 敘述區塊; end; 以下程式片段為設定a陣列的初值。 procedure InitAry; a[1]:=8; a[2]:=7; a[3]:=1; a[4]:=2; a[5]:=9; 往後只要執行以下敘述,即可設定陣列的初值。 InitAry;
範例8-1a 請將範例6-1e的泡沫排序法,分成以下三個程序完成,分別是InitAry、SortAry及 OutAry。
8-2 函式 函式(Function)語法如下: function函數名稱(參數列):傳回值型態; 函數區域變數宣告 begin 敘述區塊; 8-2 函式 函式(Function)語法如下: function函數名稱(參數列):傳回值型態; 函數區域變數宣告 begin 敘述區塊; end; 以下程式片段可傳回輸入參數a、b的極大值: function Max(a,b:integer):interger; if a>b then Max:=a; else Max:=b;
以上是使用函式名稱Max傳回值,亦可使用Result傳回值,如下式: if a>b then Result:=a; else Result:=b; 完成函式的宣告後,往後只要執行以下敘述,即可求得兩數的極大值。 m:=Max(6,2); n:=6; p:=2; m:=Max(n,p); 以上詳細程式,請自行開啟範例檔案max。
8-3 參數列 大部分的副程式(泛指程序或函數)都有參數列,參數列兩旁必須使用括號,如下所示: 8-3 參數列 大部分的副程式(泛指程序或函數)都有參數列,參數列兩旁必須使用括號,如下所示: function value(x: integer):integer procedure reference(x:integer; var y:integer):integer 括號內的文字即為參數列,x、y則稱為參數。 傳值(Value) 參數的傳遞方式,其預設值為傳值(Value),如上式的參數x。傳值是一種單向的參數傳遞,主程式將值傳給副程式後,副程式的執行結果並不回傳至主程式。
傳址(Reference) 傳址的呼叫,則是一種雙向的參數傳遞,如上式的參數y,應於參數前加上保留字var,所以是傳址呼叫。傳址呼叫時,主程式傳給副程式之後,副程式若更動參數的值,則此更動的值亦將回傳給主程式。 以下程式為傳值與傳址的示範,x是傳值,所以副程式的執行結果並不回傳給主程式,其結果為1;y則是傳址呼叫,本例於副程式中重設y值為3,所以回傳的結果,使得主程式b的值亦為3。請讀者自行開啟範例檔案reference。 //reference procedure reference(x:integer;var y:integer); begin x:=3;y:=3; end; //主程式 procedure TForm1.btnStartClick(Sender: TObject); var a,b:integer; a:=1;b:=1; reference(a,b); Label1.Caption:=IntToStr(a); //結果是 1 Label2.Caption:=IntToStr(b); //結果是 3
範例8-3a 於範例8-1a中,再將兩數交換函式化。 程式說明: Delphi允許副程式中,可再包含副程式。(筆者註:C++的所有副程式,其地位均相等,故不允許副程式中再包含副程式。)
字串的傳遞 參數中若包含字串,則參數列不可包含字串的長度,如以下用法是錯誤的。 procedure stringTest(s:string[10]); 正確寫法為: procedure stringTest(s:string);
陣列的傳遞 參數中若含有陣列,則參數列不可包含索引,例如以下式子是錯誤的。 SortAry(a:array[1...10] of integer); 應修改為: type Ta=array[1...n] of integer; SortAry(a:Ta);
範例8-3b 示範陣列的傳遞。 於範例8-1a中,陣列a是全域變數,本例則將陣列a放在參數列,可使得參數的流向更為明確。
8-4 遞迴 副程式再呼叫自己,此類程式稱為遞迴。遞迴的使用必須同時滿足以下兩個條件,否則程式會沒完沒了,終至堆疊用盡而使程式當掉。使用遞迴解題的兩個條件如下: 1. 問題須具有重複的特性,也就是在某些特性之下,可以繼續呼叫自己。 2. 重複的問題須有結束的條件。如階乘的結束條件為1!=1,費式數列的結束條件為n≦2時f(2)=1,f(1)=1。
階乘 階乘的定義是求小於等於某一數至1的連續整數之積。 階乘重複的特性為每次減1,即可自己呼叫自己,例如: 6!=6*5! 5!=5*4! 階乘結束遞迴的條件是當遞減至1時,結束遞迴。
範例8-4a 請使用遞迴法,求某一數的階乘。
費式數列 費式數列的定義如下: f(1) = 1 f(2) = 1 當n≧3時,f(n) = f(n-1) + f(n-2) 依以上定義,費氏數列前10項如下: 1,1,2,3,5,8,13,21,34,55 給任一個n,使用遞迴求其值的演算法如下: (1)只要n大於3,則分解為2項,如下: f(n) = f(n-1) + f(n-2) (2)n = 2、n = 1 則 f(1) = 1 且 f(2) = 1,並離開函式。 以n=5,解說如下: f(5) 分解成兩項,如下: = f(4)+f(3) f(4)繼續分解,f(3)先放在堆疊。 = f(3)+f(2)+f(3) f(3)繼續分解,f(2)=1,後面的f(3)還是在 堆疊。 = f(2)+f(1)+1+f(3) f(2)=1,f(1)=1,f(3)從堆疊取之分解。 = 1+1+1+f(2)+f(1) f(2)=1,f(1)=1,堆疊已空無一物,離開函式。 = 5 並傳回結果5。
範例8-4b 請以遞迴法計算費氏數列的值。
二分猜值法 以非遞迴的方式求解二分猜值法已於5-2節介紹,本單元將以遞迴法重作二分猜值法。
範例8-4c 請以遞迴法重作任意正數的平方根。
輾轉相除法 輾轉相除法已於5-2節介紹,本單元將以遞迴法重作輾轉相除法。
範例8-4d 請以遞迴法重作任意二正數的最大公因數
8-5 多載(Overloading) 多載的意思是“一種樣式有多種表現方式”,例如你有一個僕人專門幫你開門,那麼不論這個門是內推、外拉或向旁邊推,你都是下同一指令“開門”,然後你的僕人即會依照門的結構而完成開門的動作。物件導向的程式設計亦發揚此理念,讓程式設計者於程式設計階段使用相同的指令,而編譯器能於執行階段依據不同的需求,執行不同的程式片段,此即稱為多載。 於副程式的設計裏,有時會有兩種以上的副程式功能接近,有的只是參數型態或參數個數不同,此時可以使用相同的副程式名稱,以減少程式設計者的困擾。因為物件導向的程式設計均允許程式設計者在參數型態與參數個數不同時,使用相同的副程式名稱,這些相同的副程式即稱為副程式多載。以下敘述即為Sign函式的多載實例。 function Sign(const AValue: Double): TValueSign; overload; function Sign(const AValue: Integer): TValueSign; overload; function Sign(const AValue: Int64): TValueSign; overload;
副程式多載時,應於副程式後面加上管制字overload。以下程式片段,即是多載的實例,共有三個函式名稱為add的函式。 function add(x,y:real):real;overload; begin Result:=x+y; end; function add(x:integer;y:real):real;overload; function add(x,y,z:integer):integer;overload; Result:=x+y+z; 往後函式呼叫時,Delphi即會依照參數的多寡與種類,執行對應的函式。如以下式子皆可呼叫對應的函式本體。 add (3.4, 3.5); add (3, 3.5); add (3, 4, 5);
範例8-5a 示範以上副程式多載。
習題 1. 請分別以程序和函式重作範例6-1g。 2. 請以遞迴法重作範例5-3a除法運算。 3. 請以遞迴重範例5-3b的十進位轉為N 進位。 4. 請以二分猜值法重作除法運算。例如 84除 以3的商,必在4與84之間。
5. 請寫程式完成1!+2!+3!+4!+5!+……+n! (n可由使用者輸入)。 6. 請寫一個程式計算年利率為5%、6%、 6. 請寫一個程式計算年利率為5%、6%、 7%、8%時,貸款100、200、300、400萬時,每月需繳的利息,輸出格式如下: 利率 金額 5% 6% 7% 8% 100萬 200萬 300萬 400萬
7. 試寫一程式求 (1) + (1+1/2) + (1+1/2+1/3) + …+(1+1/2+1/3+…1/N)之值。 8. 試寫一個九九乘法表電腦輔助教學程式,每次電腦依序出現10題一位數乘以一位數的乘法練習題,由使用者作答,並由電腦批改評分。 9. 請以遞迴法將所輸入的中英文字串前後反轉輸出。