|
過(guò)程與函數(shù)
過(guò)程與函數(shù)是實(shí)現(xiàn)一定功能的語(yǔ)句塊,是程序中的特定功能單元??梢栽诔绦虻钠渌胤奖徽{(diào)用,也可以進(jìn)行遞歸調(diào)用。過(guò)程與函數(shù)的區(qū)別在于過(guò)程沒(méi)有返回值,而函數(shù)有返回值。
過(guò)程與函數(shù)的定義包括過(guò)程原型或函數(shù)原型、過(guò)程體或函數(shù)體的定義。過(guò)程定義的形式如下: procedure ProcedureName(ParameterList); directives;
var
LocalDeclarations;
begin
statements
end;
ProcedureName 是過(guò)程名,是有效的標(biāo)識(shí)符。ParameterList 為過(guò)程的參數(shù)列表,需要指明參數(shù)的個(gè)數(shù)和數(shù)據(jù)類(lèi)型。Directives 是一些關(guān)于函數(shù)的指令字, 如果設(shè)置多個(gè), 應(yīng)該用分號(hào)隔開(kāi)。LocalDeclarations 中定義了該函數(shù)中需要使用的一些臨時(shí)變量,通常也稱(chēng)作本地變量。在Begin 與End 之間是過(guò)程調(diào)用時(shí)實(shí)現(xiàn)特定功能的一系列語(yǔ)句。ParameterList、Directives、LocalDeclarations 和Statements 都是可選部分。 函數(shù)的定義與過(guò)程非常類(lèi)似,只是使用的保留字不同,而且多了一個(gè)返回值類(lèi)型。具體形式如下: function FunctionName(ParameterList): ReturnType; directives;
var
LocalDeclarations;
begin
statements
end;
可以將函數(shù)需要返回的數(shù)值賦值給變量Result。如果函數(shù)體中存在著一些由于判斷而產(chǎn)生的分支語(yǔ)句時(shí),就要在每一個(gè)分支中設(shè)置返回值。通常要根據(jù)函數(shù)的返回值來(lái)確定下一步的操作。注意,這里與Visual C 和Visual C++不一樣,把一個(gè)值賦給Result,函數(shù)并不會(huì)結(jié)束。
函數(shù)定義時(shí)參數(shù)列表中的參數(shù)稱(chēng)為形參,函數(shù)調(diào)用時(shí)參數(shù)列表中的參數(shù)稱(chēng)為實(shí)參。在定義的函數(shù)原型中,多個(gè)參數(shù)之間用分號(hào)隔開(kāi),同一類(lèi)型的參數(shù)可以放在一起,以逗號(hào)隔開(kāi)。函數(shù)調(diào)用的時(shí)候,在函數(shù)原型中,多個(gè)參數(shù)之間用逗號(hào)隔開(kāi)。 下面的例子定義了一個(gè)OutputNum 函數(shù),可以將一個(gè)浮點(diǎn)數(shù)按指定的精度輸出。通過(guò)這個(gè)例子,讀者可以體會(huì)函數(shù)中參數(shù)的使用: program Project1; {$APPTYPE CONSOLE} uses Sysutils; //為了使用函數(shù)Format function OutputNum(number:double;n:integer = 5):Boolean; var Str : string; //浮點(diǎn)數(shù)顯示輸出的內(nèi)容 begin if n <= -1 then //小數(shù)點(diǎn)后的位數(shù)要大于或等于0 begin Result:=False; Exit; //退出顯示函數(shù) end else begin // 設(shè)置顯示的格式 Str := Format('%*.*f', [10, n, number]); Result := True ; Writeln(Str); //顯示數(shù)據(jù) end; end; begin OutputNum(12.345); //n 默認(rèn)為5 OutputNum(123,3); //參數(shù)對(duì)數(shù)據(jù)類(lèi)型進(jìn)行升級(jí) //下面一句代碼不正確,故屏蔽掉 //OutputNum(123.456789,9.13); //參數(shù)對(duì)數(shù)據(jù)類(lèi)型不能降級(jí) //可以根據(jù)函數(shù)的返回值確定下一步的操作 if OutputNum(123.456789,-3) = False then Writeln('輸出失敗。') ; Readln; end. 運(yùn)行結(jié)果如下: 12.34500 123.000 輸出失敗。
這里有幾點(diǎn)需要說(shuō)明:
最常用的參數(shù)有3 種,分別為數(shù)值參數(shù)、變量參數(shù)和常量參數(shù)。 procedure Calculate(CalNo:Integer);
begin
CalNo := CalNo*10;
end;
用以下例程調(diào)用Calculate 函數(shù): Calculate(Number); Number 進(jìn)入Calculate 函數(shù)后,會(huì)把Number 實(shí)參拷貝給形參CalNo,在此過(guò)程中CalNo 增大10倍,但并未傳遞出來(lái),所以說(shuō)Number 值并未改變。形參和實(shí)參占用不同的內(nèi)存地址,在過(guò)程或函數(shù)被調(diào)用時(shí),將實(shí)參的值復(fù)制到形參占用的內(nèi)存中。因此,在跳出過(guò)程或函數(shù)后,形參和實(shí)參的數(shù)值是不同的,但實(shí)參的值并不發(fā)生變化。 如果想改變傳入的參數(shù)值,就需要使用變量參數(shù),即在被調(diào)用程序的參數(shù)表中的形參前加上保留字Var。例如: procedure Calculate(var CalNo : Integer); 則CalNo 并不在內(nèi)存中占據(jù)一個(gè)位置,而是指向?qū)崊umber。當(dāng)一個(gè)實(shí)參被傳遞時(shí),任何對(duì)形參所作的改變都會(huì)反映到實(shí)參中,這是因?yàn)閮蓚€(gè)參數(shù)指向同一個(gè)地址。將上一個(gè)例程中的形參CalNo前面加上Var,再以同樣的程序調(diào)用它,則在第2 個(gè)編輯框中會(huì)顯示計(jì)算的結(jié)果,把第1 個(gè)編輯框中的數(shù)值放大10 倍。這時(shí)形參CalNo 和實(shí)參Number 的值都是Nnmber 初始值的10 倍。 如果過(guò)程或函數(shù)執(zhí)行時(shí)要求不改變形參的值,最有保證的辦法是使用常量參數(shù)。在參數(shù)表的參數(shù)名稱(chēng)前加上保留字Const 就可以使一個(gè)形參成為常量參數(shù)。使用常量參數(shù)代替數(shù)值參數(shù)可以保護(hù)用戶(hù)的參數(shù),使用戶(hù)在不想改變參數(shù)值時(shí)不會(huì)意外地將新的值賦給這個(gè)參數(shù)。下面的例子可以幫助讀者加深理解: program Project1;
{$APPTYPE CONSOLE}
type
PInteger = ^Integer; //定義指針類(lèi)型
procedure P1(var N:Integer); //引用參數(shù)傳遞
begin
N:=N+1 ;
end;
procedure P2(N:Integer); //普通參數(shù)傳遞
begin
N:=N+2;
end;
procedure P3(PT:PInteger); //傳遞指針參數(shù)
begin
PT^:=PT^+3;
end;
var
i:Integer;
begin
i:=1;
P1(i); //將i 的值增加1
Writeln('i:',i);
P2(i); //希望將i 加2,但沒(méi)有實(shí)現(xiàn)
Writeln('i:',i);
P3(@i); //將i 加3
Writeln('i:',i);
Readln;
end.
運(yùn)行結(jié)果如下: i:2 i:2 i:5 這里有幾點(diǎn)需要說(shuō)明:
Result:=N+2; 在調(diào)用函數(shù)的時(shí)候使用: i:=P2(i);
為了確定傳遞的順序,可以在過(guò)程或函數(shù)定義的時(shí)候,在Directives 部分利用指令字指定傳遞的順序。來(lái)自Delphi 的聯(lián)機(jī)幫助的數(shù)據(jù),如表1-13 所示,其中列舉了Directives 部分可使用的關(guān)于函數(shù)調(diào)用約定的指令字。
program Project1; {$APPTYPE CONSOLE} function P1:Integer; //該函數(shù)將作為GetMax 函數(shù)的第1 個(gè)參數(shù) begin Writeln('P1'); Result:=0; end; function P2:Integer; //該函數(shù)將作為GetMax 函數(shù)的第2 個(gè)參數(shù) begin Writeln('P2 ') ; Result:=1; end; //參數(shù)的傳遞方式采用pascal 方式 function GetMax(N1:Integer; N2:Integer):Integer;pascal; begin Result:=N1+N2; end; begin GetMax(P1,P2); end. 運(yùn)行結(jié)果如下: 1 P1 2 P2 如果將GetMax 函數(shù)定義處的Directives 部分由Pascal 改為Stdcall,則運(yùn)行結(jié)果變?yōu)椋?/p> P2 P1 用戶(hù)可以修改GetMax 函數(shù)定義處的Directives 部分為表1-13 中的其他數(shù)值,測(cè)試結(jié)果是否一致。
4.過(guò)程和函數(shù)的重載 可以在同一個(gè)作用范圍內(nèi)給不同的過(guò)程或函數(shù)取同一個(gè)名稱(chēng),這種現(xiàn)象就叫做重載。這樣可以使編程更方便。在重載的情況下,決定使用哪個(gè)過(guò)程或函數(shù)的依據(jù)是形參和實(shí)參的一致性,即參數(shù)個(gè)數(shù)、參數(shù)類(lèi)型以及它們之間的順序,不存在一個(gè)函數(shù)調(diào)用滿足兩個(gè)重載函數(shù)的情況。另外重載函數(shù)必須用指令字Overload 來(lái)進(jìn)行說(shuō)明,函數(shù)的返回值類(lèi)型不同就不可以作為重載函數(shù)的依據(jù)。 下面的兩個(gè)函數(shù)就是重載函數(shù): function Average(a:Integer; b:Integer):Double;overload; //求整形數(shù)據(jù)的平均值 function Average(a:Double; b:Double):Double;overload; //求實(shí)數(shù)數(shù)據(jù)的平均值 下面兩條語(yǔ)句就調(diào)用了不同的函數(shù): Average(3.7,4.6); //調(diào)用的是第2 個(gè)重載函數(shù) Average(3,4); //調(diào)用的是第1 個(gè)重載函數(shù)
如果又定義了一個(gè)重載函數(shù)如下: function Average(a,b:Double;c:Double=0.0):Double;overload; //求3 個(gè)實(shí)數(shù)平均值
從上例可以看出,盡管參數(shù)的個(gè)數(shù)與上面的兩個(gè)不同,但第3 個(gè)參數(shù)設(shè)置了一個(gè)默認(rèn)值,所以當(dāng)參數(shù)調(diào)用為語(yǔ)句Average(1.1,2.2);時(shí),編譯系統(tǒng)就不知道應(yīng)該使用哪個(gè)重載函數(shù)了,因?yàn)榈? 個(gè)重載函數(shù)和第3 個(gè)重載函數(shù)都可以滿足要求,這樣就會(huì)出現(xiàn)一個(gè)編譯錯(cuò)誤。
在Object Pascal 中,過(guò)程或函數(shù)必須先說(shuō)明再調(diào)用。以上規(guī)則在遞歸調(diào)用時(shí)屬于例外情況。所謂遞歸調(diào)用,是指函數(shù)A 調(diào)用函數(shù)B,而函數(shù)B 又調(diào)用函數(shù)A 的情況,或是指一個(gè)函數(shù)調(diào)用自身的特殊情況。在遞歸調(diào)用中,函數(shù)要進(jìn)行前置,即在函數(shù)或過(guò)程的標(biāo)題部分最后加上保留字Forward。下文的例子是一個(gè)遞歸調(diào)用的典型例子: program Project1; {$APPTYPE CONSOLE} var Alpha:Integer; procedure Test2(var A:Integer);forward; //Test2 被說(shuō)明為前置過(guò)程 procedure Test1(var A:Integer); begin A:=A-1; if A>0 then Test2(A); //經(jīng)前置說(shuō)明,調(diào)用未執(zhí)行的過(guò)程Test2 writeln(A); end; procedure Test2(var A:Integer); //經(jīng)前置說(shuō)明的Test2 的執(zhí)行部分 begin A:=A div 2; if A>0 then Test1(A); //在Test2 中調(diào)用已執(zhí)行的過(guò)程Test1 end; begin Alpha := 15; //給Alpha 賦初值 Test1(Alpha); //第1 次調(diào)用Test1,遞歸開(kāi)始 end. 程序開(kāi)始時(shí)給Alpha 賦初值,并實(shí)現(xiàn)先減1 再除2 的循環(huán)遞歸調(diào)用,直到Alpha 小于0 為止。
規(guī)范化命名
在系統(tǒng)開(kāi)發(fā)的過(guò)程中,常常要為變量、類(lèi)、對(duì)象、函數(shù)和文件等命名。一般在開(kāi)發(fā)需求或設(shè)計(jì)階段就必須制定出一套完整、實(shí)用的命名規(guī)則。這樣,在很大程度上可以提高系統(tǒng)開(kāi)發(fā)的效率,便于不同模塊之間的接口,方便系統(tǒng)的維護(hù)。
|
|
|
來(lái)自: 佚名2016 > 《編程設(shè)計(jì)》