第7章-過程與函數(shù)_第1頁
第7章-過程與函數(shù)_第2頁
第7章-過程與函數(shù)_第3頁
第7章-過程與函數(shù)_第4頁
第7章-過程與函數(shù)_第5頁
已閱讀5頁,還剩122頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

第7章過程與函數(shù)目錄大綱第七章過程與函數(shù)7.1過程7.1.1事件過程的創(chuàng)建與調(diào)用7.1.2通用過程7.2函數(shù)7.2.1函數(shù)的定義7.2.2函數(shù)的應(yīng)用舉例7.3參數(shù)傳遞7.3.1變量參數(shù)7.3.2值參數(shù)和常量參數(shù)7.3.3默認(rèn)參數(shù)7.4子程序的嵌套與遞歸7.4.1子程序的嵌套7.4.2子程序的遞歸7.5變量的作用域7.5.1公有變量和私有變量7.5.2全局變量和局部變量7.6小結(jié)過程(procedure)與函數(shù)(function)是實(shí)現(xiàn)面向?qū)ο缶幊趟枷氲闹匾侄?。在Delphi中將各個功能模塊做成函數(shù)或者過程的形式,供程序不同位置的調(diào)用,被調(diào)用的函數(shù)和過程也成為子程序。使用函數(shù)和過程不僅可以將一個大的、復(fù)雜的問題簡單化,而且還可以使程序更加清晰、條理。過程與函數(shù)的區(qū)別在于過程沒有返回值,而函數(shù)有返回值。一般來說定義過程的目的是為了實(shí)現(xiàn)某個功能、執(zhí)行某個操作,而定義函數(shù)的目的在于計(jì)算得到某個值。7.1過程在Delphi中過程分為系統(tǒng)標(biāo)準(zhǔn)過程和自定義過程。系統(tǒng)標(biāo)準(zhǔn)過程是系統(tǒng)內(nèi)部定義的,無需定義即可直接調(diào)用,如第二章所講的過程EncodeDate過程,用戶無需定義它,即可直接調(diào)用實(shí)現(xiàn)將年、月、日合并成為日期類型的功能。自定義過程也分為兩類,即事件過程和通用過程。事件過程的執(zhí)行有兩種方式,一種是事件驅(qū)動,即一個事件發(fā)生了,系統(tǒng)自動執(zhí)行相應(yīng)的事件過程,還有一種就是調(diào)用并執(zhí)行事件過程。事件過程與對象有關(guān),是Delphi應(yīng)用程序中最重要的過程。通用過程不依附于對象,通用過程一般用來執(zhí)行某些操作,完成某個功能。有些功能代碼在程序的多處出現(xiàn),我們把它做成過程,在多處調(diào)用它,這樣可以使得程序清晰、簡潔,避免書寫重復(fù)的代碼,這就是我們設(shè)計(jì)通用過程的理由。為了加深對過程以及過程調(diào)用的理解,我們需要重新回顧一下事件過程的定義和調(diào)用。7.1.1事件過程的創(chuàng)建與調(diào)用在對象監(jiān)視器中選擇某個對象(或者在窗體中單擊該對象),然后在對象監(jiān)視器的“Event”頁中選擇相應(yīng)的事件并雙擊右邊的空白區(qū)域,Delphi將自動產(chǎn)生一個默認(rèn)的事件過程。事件過程的名稱是對象名加上事件類型名,如Button1的OnClick事件對應(yīng)的事件過程就是ButtonClick。當(dāng)一個事件發(fā)生后,Delphi會自動執(zhí)行相應(yīng)的事件過程。當(dāng)然,一個事件過程也可以被多個事件甚至多個對象共享。方法是,首先為某個事件創(chuàng)建事件過程,然后在創(chuàng)建其它事件的事件過程時,從事件名稱右邊的下拉組合框中選擇已經(jīng)建立的事件過程名稱即可。共享事件的好處是,當(dāng)共享事件過程的多個事件中任何一個事件發(fā)生時都會執(zhí)行事件過程。有時候很多相似組件共享事件過程可以減少代碼的編寫?!纠?-1】在窗體上添加組件Image1~Image9共9個Image組件,添加Shape組件若干,用于做Image組件的邊框。設(shè)計(jì)界面如圖7-1所示。本程序是兩人對弈,雙方在9格的棋盤上先后布棋,單擊Image在Image上顯示不同的圖片(圓或者叉),哪方的三個圖片先成一條直線,哪方獲勝。步驟如下:(1)將Image1~Image9的tag屬性分別設(shè)置為1~9。(2)定義全局變量:n:integer;flag:array[1..9]ofinteger;說明:①n用于控制步數(shù),奇數(shù)和偶數(shù)步分別布“叉”棋和“圓”棋。②Flag數(shù)組用于判斷某個位置的棋的性質(zhì):

flag[x]=-1:表示x位置沒有布棋;

flag[x]=0:表示x位置布“圓”棋;flag[x]=1:表示x位置布“叉”棋。(3)在TForm1.FormCreate事件過程中將所有位置的棋子置為沒有布棋(flag[i]:=-1,I從1到9),將n置初值為0,以后每布一顆棋子n就加1。代碼如下:procedureTForm1.FormCreate(Sender:TObject);vari:integer;beginn:=0;//還沒有布棋子

fori:=1to9doflag[i]:=-1;//9個Image均沒有布棋子end;(4)在對象監(jiān)視器中選定9個Image組件,在Event中選擇OnClick事件并雙擊空白區(qū)域,編寫如下代碼:procedureTForm1.Image9Click(Sender:TObject);beginif(flag[(senderastimage).Tag]=-1)then//如果該位置沒有布棋子

beginn:=n+1;ifnmod2=0then//偶數(shù)布“圓”棋子

begin(senderastimage).picture.loadfromfile('yuan.bmp');flag[(senderastimage).Tag]:=0;//布子后,做上標(biāo)記

endelse//奇數(shù)布“叉”棋子

begin(senderastimage).picture.loadfromfile('cha.bmp');flag[(senderastimage).Tag]:=1;//布子后,做標(biāo)記

end;end;……//省略判斷勝負(fù)的代碼end;(5)運(yùn)行程序,界面如圖7-2所示。說明:(1)本程序9個Image組件的OnClick事件都共用同一個事件過程,這樣顯然節(jié)省代碼編寫工作量。(2)我們?nèi)菀字辣境绦蛑斜粏螕舻慕M件表示為(senderastimage),因此可以很方便地為它設(shè)置picture屬性。(3)全局變量n用于控制布棋的奇偶步數(shù),根據(jù)n是否能被2整除可知目前應(yīng)該布“叉”棋還是布“圓”棋。(4)tag的作用有兩個。一是用于區(qū)分不同位置的Image組件,這樣可以方便設(shè)置該位置的棋子屬性(是否有棋,有什么棋);二是用于判斷勝負(fù),例如:flag[(senderastimage).Tag](tag為1、2、3的時候)的值都是0,顯然說明“圓”棋獲勝等等。請讀者自己完成判斷獲勝的代碼。(5)上面是9個組件共用一個事件過程。當(dāng)然,也可以只為Image9編寫過程TForm1.Image9Click。而在Image1~Image8的事件過程中調(diào)用TForm1.Image9Click事件過程。例如:procedureTForm1.Image1Click(Sender:TObject);//Image2~Image8類似beginForm1.Image9Click(Sender)end;還可以寫成:procedureTForm1.Image1Click(Sender:TObject);beginForm1.Image9Click(form1.Image1)end;通過本例,讀者應(yīng)該對事件過程的創(chuàng)建與調(diào)用有一個較深的認(rèn)識。7.1.2通用過程通用過程要遵循先定義后使用的原則,只用經(jīng)過定義的過程才能夠被程序調(diào)用,過程是沒有返回值的,因此過程的調(diào)用就是一個獨(dú)立執(zhí)行的語句。1.通用過程的定義通用過程的定義語法形式為:Procedure<過程名>[(<形參表>)];[局部聲明];begin<語句序列>;end;<形參表>的格式為:[Const|Var]<形參名>:類型說明:(1)保留字Procedure是定義通用過程的首部,過程名遵循標(biāo)識符的命名規(guī)則。(2)<形參表>由若干個形式參數(shù)組成,形式參數(shù)的類型和個數(shù)都必須給定,同類型的形式參數(shù)之間用逗號隔開,不同類型的形式參數(shù)之間用分號隔開,如果沒有形式參數(shù),則括號可省略。例如:m,n:integer;vargys:integer(3)局部聲明部分可以聲明局部變量、常量、類型等等。(4)程序體以begin開始,以end結(jié)束,end之后是分號。2.通用過程的調(diào)用程序執(zhí)行某個過程稱之為調(diào)用,調(diào)用的格式為:過程名(實(shí)參表);說明:(1)實(shí)參表中的參數(shù)的個數(shù)和類型必須和形參一致,實(shí)參是按照在參數(shù)表中的先后順序?qū)?shù)值依次傳遞給形參的。(2)如果形參用前冠以var,則相應(yīng)的實(shí)參必須是變量,否則只需要是同類型的表達(dá)式即可。3.通用過程舉例【例7-2】編寫一個過程,輸出m行“*”號,要求第一行輸出1個“*”號,以后每行比上一行多出一個“*”,要求使用控制臺應(yīng)用程序。設(shè)計(jì)步驟如下:(1)選擇“File|New|Other…”出現(xiàn)新建項(xiàng)目對話框,在新建項(xiàng)目對話框中選擇“ConsoleApplicaion”,出現(xiàn)代碼編輯器。(2)在代碼編輯器中輸入程序,如下:programProject1;{$APPTYPECONSOLE}usesSysUtils;varn:integer;procedureprin(m:integer);vari,j:integer;beginfori:=1tomdobeginforj:=1toidowrite('*');writeln;end;end;beginwrite('輸入行數(shù):');readln(n);prin(n);readln;end.(3)運(yùn)行程序,輸入行數(shù)6,結(jié)果如圖7-3所示。說明:(1)本程序定義了變量n,在主程序和過程里面都是有效的,定義了i,j僅在過程中有效,是局部變量。(2)形參m是整型,實(shí)參n也應(yīng)該是整型?!纠?-3】編寫通用過程,用于求兩個數(shù)或者三個數(shù)的最大公約數(shù)。界面如圖7-4所示。分析:由于求公約數(shù)在多處出現(xiàn),因此最好把它定義為子程序,以便在多處調(diào)用,鑒于目前讀者只學(xué)了過程,所以本例編寫通用過程來解決問題。步驟如下:(1)求兩個數(shù)m和n的最大公約數(shù)有一種方法將做碾轉(zhuǎn)相除法,即:求m和n的最大公約數(shù)就是求n和mmodn的最大公約數(shù),這樣一來問題就變成了求n和mmodn的最大公約數(shù)了。將n看成新的m,mmodn看成新的n繼續(xù)使用碾轉(zhuǎn)相除法直到n為0,此時的m就是所求的最大公約數(shù)。根據(jù)分析過程gys定義如下:proceduregys(m,n:integer;varresult:integer);beginrepeatresult:=m;m:=n;n:=resultmodn;untiln=0;result:=m;end;說明:形式參數(shù)result必須定義為變量參數(shù),以便將結(jié)果回傳給實(shí)際參數(shù),這點(diǎn)將在后面的章節(jié)中仔細(xì)講解。(2)編寫B(tài)utton1的OnClick事件過程如下:procedureTForm1.Button1Click(Sender:TObject);varresult1:integer;begingys(6,9,result1);panel2.Caption:='最大公約數(shù)為:'+inttostr(result1);//Panel2是小面板end;(3)編寫B(tài)utton2的OnClick事件過程如下:procedureTForm1.Button2Click(Sender:TObject);varresult1:integer;begingys(12,16,result1);panel2.Caption:='最大公約數(shù)為:'+inttostr(result1);end;(4)編寫B(tài)utton3的OnClick事件過程如下:procedureTForm1.Button3Click(Sender:TObject);varresult1,result2:integer;begingys(8,12,result1);//帶回的result1為8和12的最大公約數(shù)gys(result1,18,result2);//求result1和18的最大公約數(shù),結(jié)果由result2帶回panel2.Caption:='最大公約數(shù)為:'+inttostr(result2);end;(5)運(yùn)行程序,結(jié)果如圖7-5所示。7.2函數(shù)和過程一樣函數(shù)也是子程序的一種形式,函數(shù)與過程的區(qū)別在于函數(shù)有返回值,過程沒有返回值。Delphi中的函數(shù)同樣分為標(biāo)準(zhǔn)函數(shù)和自定義函數(shù),標(biāo)準(zhǔn)函數(shù)如sin,cos、exp、datetostr等,標(biāo)準(zhǔn)函數(shù)無需定義,直接調(diào)用即可。本節(jié)講述自定義函數(shù),自定義函數(shù)要先定義,后調(diào)用,調(diào)用的方法和標(biāo)準(zhǔn)函數(shù)一樣。7.2.1函數(shù)的定義自定義函數(shù)要遵循先定義后使用的原則,只用經(jīng)過定義的函數(shù)才能夠被程序調(diào)用,函數(shù)定義的格式是:Function<函數(shù)名>[(<形參表>)]:<函數(shù)類型>;[局部聲明];begin<語句序列>;end;<形參表>的格式為:[Const|Var]<形參名>:類型說明:(1)保留字Function是定義函數(shù)的首部,函數(shù)名遵循標(biāo)識符的命名規(guī)則。(2)<形參表>由若干個形式參數(shù)組成,形式參數(shù)的類型和個數(shù)都必須給定,同類型的形式參數(shù)之間用逗號隔開,不同類型的形式參數(shù)之間用分號隔開,如果沒有形式參數(shù),則括號可省略。例如:m,n:integer;vargys:integer(3)局部聲明部分可以聲明局部變量、常量、類型等等。(4)程序體以begin開始,以end結(jié)束,end之后是分號(5)<函數(shù)類型>是函數(shù)返回值的類型,函數(shù)是有返回值的。函數(shù)的返回值是通過函數(shù)名帶回的,因此,在函數(shù)定義部分需要給函數(shù)名賦值,如果在函數(shù)體中不給函數(shù)名賦值,則函數(shù)的返回值就是默認(rèn)值,數(shù)值型的默認(rèn)值是0,布爾類型就是false,字符類型就是空字符等等?!纠?-4】編寫一個自定義函數(shù),用于求整數(shù)n的階乘。functionfac(n:integer):int64;//返回值定義為integer容易溢出

varm:int64;i:integer;beginm:=1;fori:=1tondom:=m*i;fac:=m;end;7.2.2函數(shù)的應(yīng)用舉例【例7-5】求100以內(nèi)的素?cái)?shù)之和。分析:因?yàn)楸境绦蛐枰嗵幥笏財(cái)?shù),因此可以考慮定義一個函數(shù)用于判斷某個數(shù)是否為素?cái)?shù)。這個函數(shù)是布爾類型,返回值為true表示這個數(shù)是素?cái)?shù),返回值為false表示這個數(shù)不是素?cái)?shù)。步驟如下:(1)設(shè)計(jì)界面如圖7-6所示。(2)設(shè)置函數(shù)如下:functionprime(n:integer):boolean;vari:integer;beginprime:=true;fori:=2totrunc(sqrt(n))doifnmodi=0thenprime:=false;end;說明:首先假設(shè)n是素?cái)?shù),令prime:=true,然后在2~之間尋找n的因子,如果找到n的因子則前面的假設(shè)是錯誤的,重新令prime:=false。如果找不到任何因子則n是素?cái)?shù),此時prime仍然保持為初始假設(shè)的true值。(3)編寫B(tài)itBtn1的事件過程,如下:procedureTForm1.BitBtn1Click(Sender:TObject);vars,i:integer;begins:=0;fori:=2to100doifprime(i)thens:=s+i;panel2.Caption:='100以內(nèi)素?cái)?shù)之和為'+inttostr(s);end;(4)程序運(yùn)行,界面如圖7-7所示?!纠?-6】求兩個數(shù)的最大公約數(shù)和最小公倍數(shù)。分析:求兩個數(shù)的最大公約數(shù)可以使用碾轉(zhuǎn)相除法,而最小公倍數(shù)和最大公約數(shù)有這樣的數(shù)學(xué)關(guān)系,即:m和n的最小公倍數(shù)乘以它們的最大公約數(shù)剛好等于m和n的乘積。因此,只要求出最大公約數(shù),就可以求出最小公倍數(shù)。因?yàn)槎叩奶厥獾臄?shù)學(xué)關(guān)系,本例將求最大公約數(shù)和最小公倍數(shù)定義為一個函數(shù)。設(shè)計(jì)步驟如下:(1)設(shè)計(jì)界面如圖7-8所示。設(shè)計(jì)界面如圖7-8所示。(2)編寫函數(shù)的代碼如下:functiondivmul(m,n,flag:integer):integer;vart,a,b:integer;begina:=m;b:=n;//在m和n值改變之前先將原值保留到a和b中以備以后使用repeatt:=m;m:=n;n:=tmodn;

untiln=0;ifflag=1thendivmul:=m//最大公約數(shù)

elsedivmul:=a*bdivm;//最小公倍數(shù)end;說明:①由于求m和n的最小公倍數(shù)需要使用到最大公約數(shù)和m和n,所以先將m和n的值先保留到a和b中,以便在求最小公倍數(shù)的過程中使用。②本自定義函數(shù)的參數(shù)中巧妙地定義了一個flag,flag值為1就是求最大公約數(shù)的標(biāo)志,flag值為其它值表示求最小公倍數(shù)。(3)編寫B(tài)utton1的事件過程,如下:procedureTForm1.Button1Click(Sender:TObject);varm,n:integer;beginm:=strtoint(edit1.Text);n:=strtoint(edit2.Text);edit3.Text:=inttostr(divmul(m,n,1));//edit3中是最大公約數(shù)

edit4.Text:=inttostr(divmul(m,n,0));//edit4中是最小公倍數(shù)end;(4)運(yùn)行程序,結(jié)果如圖7-9所示。說明:(1)【例7-5】巧妙地將函數(shù)結(jié)果定義為布爾類型,然后在程序中根據(jù)prime(i)的值來決定是否加到s中。(2)【例7-6】使用到參數(shù)flag,根據(jù)參數(shù)flag的值的不同,函數(shù)返回不同的值,這也是程序的巧妙之處。這兩個例題各有千秋,讀者應(yīng)該舉一反三,靈活運(yùn)用。(3)需要強(qiáng)調(diào)的是函數(shù)的使用必須遵循先定義后使用的原則,也就是說函數(shù)定義的代碼必須寫在調(diào)用程序之前。7.3參數(shù)傳遞在定義函數(shù)或過程的時候所使用的參數(shù)稱之為形式參數(shù),簡稱形參,在調(diào)用函數(shù)或過程的時候所使用的參數(shù)稱之為實(shí)際參數(shù),簡稱實(shí)參。實(shí)參和形參必須一一對應(yīng),而且對應(yīng)的參數(shù)的類型也必須相同。參數(shù)傳遞是指調(diào)用程序按照先后順序?qū)?shí)際參數(shù)一一傳遞給對應(yīng)的形式參數(shù)。按照參數(shù)傳遞方式的不同,形式參數(shù)還可以分為變量參數(shù)、常量參數(shù)、值參數(shù)。7.3.1變量參數(shù)在過程或者函數(shù)定義的時候,如果形式參數(shù)前冠以保留字var,則表示該參數(shù)是變量參數(shù)。變量參數(shù)的值傳遞方式是地址傳遞,所謂地址傳遞是指實(shí)際參數(shù)將自己的內(nèi)存地址傳遞給形式參數(shù),這樣一來形式參數(shù)實(shí)際上和實(shí)際參數(shù)表示同一個存儲單元。形式參數(shù)值的改變將會影響實(shí)際參數(shù)的值。例如,在【例7-3】中利用過程proceduregys(m,n:integer;varresult:integer)求公約數(shù),在定義過程的時候形式參數(shù)result就是變參,而過程:proceduregys(m,n:integer;varresult:integer);beginrepeatresult:=m;m:=n;n:=resultmodn;untiln=0;result:=m;end;中result的值就是最大公約數(shù),這個變量參數(shù)的值通過地址傳遞給調(diào)用程序中的變量result1,在Tform1.ButtonClick中result1和變量參數(shù)result就是一個存儲單元。procedureTForm1.Button1Click(Sender:TObject);varresult1:integer;begingys(6,9,result1);panel2.Caption:='最大公約數(shù)為:'+inttostr(result1);end;說明:由于形式參數(shù)和實(shí)際參數(shù)表示同一個存儲單元,因此實(shí)際參數(shù)必須是變量。7.3.2值參數(shù)和常量參數(shù)在定義函數(shù)或者過程的時候,如果參數(shù)前被冠以保留字const,那么該參數(shù)就是常量參數(shù),如果參數(shù)前既沒有保留字var也沒有保留字const,那么該參數(shù)就是值參數(shù)。1.值參數(shù)值參數(shù)的值的傳遞是按照值來傳遞的,即將實(shí)參的值傳遞給形參,形參和實(shí)參不是一個存儲單元,形參值的改變,不會影響實(shí)參。2.常量參數(shù)無論實(shí)參是否是變量,常量參數(shù)在過程中,其值不能改變。7.3.3默認(rèn)參數(shù)在定義函數(shù)或者過程的時候,可以給形式參數(shù)指定一個默認(rèn)值,指定默認(rèn)值的方法是:在形式參數(shù)后按使用“=”,并給出一個具體的值。例如:Procedureprintline(m:integer;n:integer=5);對于上面定義的過程,下面的兩個調(diào)用語句是等價的:prinline(a,5);prinline(a);Delphi規(guī)定,在函數(shù)或者過程定義的時候,不能讓前面的形式參數(shù)有默認(rèn)值而后面的參數(shù)卻沒有默認(rèn)值。例如下面這樣定義是不行的:Procedureprintline(m:integer=5;n:integer);這是因?yàn)镈elphi的參數(shù)傳遞是從前往后依次按照順序傳遞的?!纠?-7】教職工信息錄入系統(tǒng)。教職工的信息包括姓名、性別、民族。因?yàn)榻搪毠ぶ心新毠ざ嗯毠ど?,漢族教職工多少數(shù)民族教職工少,基于此,為了提高數(shù)據(jù)錄入速度,在定義過程的時候?qū)⒛行?、漢族作為默認(rèn)值。設(shè)計(jì)步驟如下:(1)在窗體上添加組件面板Panel1、多行編輯框Memo1、單行編輯框Edit1、Edit2、Edit3、標(biāo)簽Label1、Label2、Label3、按鈕Button1,設(shè)置屬性。設(shè)計(jì)界面如圖7-10所示圖7-10教職工信息輸入窗口(2)編寫自定義過程完成教職工信息添加,自定義過程如下:procedureimport(xm:string;xb:widestring='男';mz:string='漢族');beginxm:=xm+'';//每個人的姓名長度可能不一樣xm:=copy(xm,1,8);//在姓名后加空格,補(bǔ)足8位xb:=xb+'';//性別之后空兩個小格form1.Memo1.Lines.Add(xm+''+xb+''+mz);end;說明:姓名是必須的,性別是默認(rèn)的,默認(rèn)值“男”,民族是默認(rèn)的(3)編寫B(tài)utton1的事件過程,如下:procedureTForm1.Button1Click(Sender:TObject);vara:word;beginiflength(trim(edit1.Text))=0hena:=messagedlg('請輸入姓名',mterror,[mbok],1)//姓名不可少

elseiflength(trim(edit2.Text))=0//性別默認(rèn),此時民族也取默認(rèn)值

thenimport(edit1.Text)//僅有一個參數(shù),是姓名

elseiflength(trim(edit3.Text))=0//性別不默認(rèn),但是民族取默認(rèn)值

thenimport(edit1.Text,edit2.Text)//此時,有兩個參數(shù)姓名和性別

elseimport(edit1.Text,edit2.Text,edit3.Text);//三個編輯框都不空,三個參數(shù),分別是姓名、性別、民族edit1.Text:='';edit2.Text:='';edit3.Text:='';edit1.SetFocus;end;說明:①男性和漢族是默認(rèn)值。在輸入時如果只輸入姓名,則性別取默認(rèn)值“男性”,此時即使輸入民族也沒有用,民族此時也取默認(rèn)值“漢族”。②在輸入信息的時候,如果輸入了姓名、性別,若沒有輸入民族,此時民族取默認(rèn)值“漢族”。(4)運(yùn)行程序,結(jié)果如圖7-11所示。7.4子程序的嵌套與遞歸在子程序(函數(shù)或者過程)中定義了另外的子程序(函數(shù)或者過程)就稱之為子程序(函數(shù)或者過程)的嵌套。在Delphi中子程序(函數(shù)或者過程)直接或者間接調(diào)用它自己就稱之為遞歸,遞歸分為直接遞歸和間接遞歸。7.4.1子程序的嵌套子程序中可以定義子程序,而小的子程序中還可以定義更小的子程序,這就是子程序的層數(shù)。Delphi規(guī)定上級子程序必須完整地包含下級子程序,如圖7-12所示,不允許局部包含,也就是如圖7-13所示的交叉包含。圖7-12正確的嵌套關(guān)系

【例7-8】輸入m,n的值求組合數(shù)C。分析:已知C=,因此要想求C可以定義階乘函數(shù),求出了階乘,就可以求出C。根據(jù)分析,設(shè)計(jì)步驟如下:(1)設(shè)計(jì)界面如圖7-14所示。(2)編寫comb組合函數(shù),代碼如下:functioncomb(m,n:integer):real;varx,y,z:real;functionfac(n:integer):real;varp:real;i:integer;beginp:=1;fori:=1tondop:=p*i;fac:=p;end;beginx:=fac(m);y:=fac(n);z:=fac(m-n);comb:=x/(y*z);end;(3)單擊Button1,編寫B(tài)utton1的OnClick事件過程。如下:procedureTForm1.Button1Click(Sender:TObject);varm,n:integer;beginn:=strtoint(edit1.Text);m:=strtoint(edit2.Text);ifn>mthenedit3.Text:='m必須>=n!'elseedit3.Text:=floattostr(comb(m,n));end;(4)運(yùn)行程序,如圖7-15所示。

圖7-15程序運(yùn)行結(jié)果說明:這里將fac函數(shù)和comb函數(shù)的返回值都定義為real類型。因?yàn)閕nteger或者int64表示數(shù)的范圍有限。如果定義為int64只能夠求出m小于等于20以內(nèi)的組合數(shù)。如果定義為integer則適用范圍更小。為了防止在編輯框中輸入非法的字符,可以編寫如下代碼:procedureTForm1.Edit1KeyPress(Sender:TObject;varKey:Char);beginifnot((key>=#48)and(key<=#57)or(key=#8))//可以輸入數(shù)字和Backspacethenkey:=#0//#48是字符“0”,#57是字符“9”,#8是Backspaceend;procedureTForm1.Edit2KeyPress(Sender:TObject;varKey:Char);beginifnot((key>=#48)and(key<=#57)or(key=#8))thenkey:=#0end;【例7-9】輸入m,n的值求組合數(shù)C。要求使用嵌套過程的方法來做。步驟如下:(1)設(shè)計(jì)界面,省略。(2)編寫自定義過程,代碼如下:procedurecomb(m,n:integer;varcom:real);varx,y,z:real;procedurefac(n1:integer;varfa:real);vari:integer;

beginfa:=1;fori:=1ton1dofa:=fa*i;end;beginfac(m,x);fac(n,y);fac(m-n,z);com:=x/(y*z);end;(2)編寫B(tài)utton1的OnClick事件過程如下:procedureTForm1.Button1Click(Sender:TObject);varm,n:integer;c:real;beginn:=strtoint(edit1.Text);m:=strtoint(edit2.Text);ifn>mthenedit3.Text:='m必須>=n!'elsebegincomb(m,n,c);edit3.Text:=floattostr(c);end;end;(3)編寫其他事件過程的代碼,如下:procedureTForm1.Edit1KeyPress(Sender:TObject;varKey:Char);beginifnot((key>=#48)and(key<=#57)or(key=#8))thenkey:=#0end;procedureTForm1.Edit2KeyPress(Sender:TObject;varKey:Char);beginifnot((key>=#48)and(key<=#57)or(key=#8))thenkey:=#0end;(4)程序運(yùn)行結(jié)果與【例7-9】完全一樣。7.4.2子程序的遞歸子程序直接或者間接地調(diào)用它自己就稱之為子程序的遞歸,子程序的遞歸分為函數(shù)的遞歸和過程的遞歸。例如:求自然數(shù)n的階乘,可以使用遞歸定義為:n!=還有:求m和n的最大公約數(shù)gys,可以定義為:m和n的公約數(shù)=從上面兩個遞歸看出,要想定義遞歸子程序,必須符合兩個條件:(1)一個規(guī)模比較大的問題,可以分解為若干個規(guī)模較小的同樣類型的問題。(2)規(guī)模小到一定程度有固定的解。1.函數(shù)的遞歸【例7-10】求自然數(shù)n的階乘,已知:n!=分析:本題使用函數(shù)的遞歸,定義fac(n)為real類型。設(shè)計(jì)步驟為:(1)設(shè)計(jì)界面,如圖7-16所示。(2)編寫自定義函數(shù),如下:functionfac(n:integer):real;beginifn=0thenfac:=1elsefac:=n*fac(n-1);end;(3)編寫B(tài)utton1的OnClick事件過程如下:procedureTForm1.Button1Click(Sender:TObject);varn:integer;beginn:=strtoint(edit1.Text);edit2.Text:=floattostr(fac(n))end;(4)為了防止其他非法字符輸入,可以編寫過程:procedureTForm1.Edit1KeyPress(Sender:TObject;varKey:Char);beginifnot((key>=#48)and(key<=#57)or(key=#8))thenkey:=#0end;(5)運(yùn)行結(jié)果如圖7-17所示?!纠?-11】求m和n的最大公約數(shù)。分析:已知m和n的最大公約數(shù)等于n和mmodn的最大公約數(shù),而m和0的最大公約數(shù)為m。符合遞歸的兩個條件。步驟如下:(1)設(shè)計(jì)界面,如圖7-18所示。(2)編寫遞歸的函數(shù)如下:functionfac(m,n:int64):int64;beginifn=0thenfac:=melsefac:=fac(n,mmodn)end;(3)編寫B(tài)utton1的OnClick事件過程如下:procedureTForm1.Button1Click(Sender:TObject);vara,b:int64;begina:=strtoint(edit1.Text);b:=strtoint(edit2.Text);edit3.Text:=inttostr(fac(a,b))end;(4)運(yùn)行結(jié)果如圖7-19所示2.過程的遞歸【例7-12】n階Hanno塔問題。設(shè)有三個分別命名為a,b,c的塔座,在a上有n個直徑大小不等的圓盤,從大到小放置(較小的圓盤放置在較大的圓盤上)?,F(xiàn)要求將這n個圓盤移動到c座上,并且依舊按照原來的順序放置(較小的圓盤放置在較大的圓盤上)可以使用b塔座過渡。圓盤移動時必須遵守如下規(guī)則:①每次只許移動一個盤子。②圓盤可以放置在任何一個圓盤上。③任何時刻都不允許較大圓盤放置在較小圓盤上。分析:這是典型的遞歸問題。實(shí)際上,將n個圓盤從a座移動到c座可以分3步進(jìn)行。①將a座上面的n-1個較小的圓盤移動到b座,中間可以經(jīng)過c座過渡。②再將a座上最大的那個圓盤直接移動放置在c盤上。③再將b盤上的n-1個圓盤全部移動到c盤上,中間可以經(jīng)過a過渡。這3步都是規(guī)模較小的同類的問題,而且當(dāng)只有一個圓盤時可以直接移動。根據(jù)分析,設(shè)計(jì)步驟如下:(1)設(shè)計(jì)界面,如圖7-20所示。(2)編寫遞歸過程,如下:procedurehanno(a,b,c:char;n:integer);vars:string;beginifn=1thenbegins:='Move'+a+'to'+c;//n=1,只有一步可以完成移動

form1.Memo1.Lines.Add(s);//把移動方法輸出在memo中

endelsebegin//n>1,分為3步進(jìn)行

hanno(a,c,b,n-1);//第①步

s:='Move'+a+'to'+c;//第②步

form1.Memo1.Lines.Add(s);hanno(b,a,c,n-1);//第③步

end;end;(3)編寫B(tài)utton1的OnClick事件過程如下:procedureTForm1.Button1Click(Sender:TObject);varfirst,second,last:string[1];n:integer;beginmemo1.Lines.Clear;//清空memofirst:=trim(edit1.Text);//初始塔座

second:=trim(edit2.Text);//過渡塔座

last:=trim(edit3.Text);//目標(biāo)塔座

n:=strtoint(edit4.Text);//圓盤個數(shù)

hanno(first[1],second[1],last[1],n)end;(4)運(yùn)行結(jié)果,如圖7-21所示。問題:可否將n階Hanno塔問題分解成下面3步進(jìn)行:①將a座上面的最小的圓盤移動到b座。②再將a座上剩下的n-1的圓盤移動到c座,中間可以經(jīng)過b過渡。③再將b盤上的那個最小的圓盤移動到c盤上。請讀者思考。7.5變量的作用域變量的作用域是指變量在哪些范圍可以使用。當(dāng)一個程序包含多個子程序的時候,各個子程序中都可以定義變量,這些變量只能夠在所定義的子程序中有效,稱之為局部變量,而在Delphi中還允許用戶定義全局的變量。7.5.1公有變量和私有變量在單元接口部分聲明的變量稱之為公有變量,公有變量可以被其它單元引用。單元接口interface決定了本單元哪些變量是公有變量。其他單元需要使用該公有變量只需要在uses部分加上該單元即可。在單元的實(shí)現(xiàn)部分(implementation)部分聲明的變量屬于死右邊量,只能被本單元使用。7.5.2全局變量和局部變量在子程序中定義的變量,只能夠在該子程序中有效,稱之為局部變量。而在子程序之前,在Implementation之后定義的變量可以被本單元所有子程序所使用,屬于全局變量。一般來說要盡量多使用局部變量,防止全局變量的副作用,如果需要在多個子程序之間交換數(shù)據(jù)則可以通過全局變量來進(jìn)行?!纠?-13】在【例7-12】中,如果我們希望在移動圓盤之前顯示第多少步,此時,可以考慮使用全局變量。步驟省略,修改后的程序如下:implementation{$R*.dfm}varcount:int64;//定義全局變量,用于表示移動的次數(shù)procedurehanno(a,b,c:char;n:integer);vars:string;beginifn=1thenbegincount:=count+1;//無論哪次調(diào)用過程移動圓盤count值都有效,也就是在上次基礎(chǔ)上再加1s:='第'+inttostr(count)+'步,Move'+a+'to'+c;form1.Memo1.Lines.Add(s);end

elsebeginhanno(a,c,b,n-1);count:=count+1;//無論哪次調(diào)用過程移動圓盤count值都有效,也就是在上次基礎(chǔ)上再加1s:='第'+inttostr(count)+'步,Move'+a+'to'+c;form1.Memo1.Lines.Add(s);hanno(b,a,c,n-1);end;end;procedureTForm1.Button1Click(Sender:TObject);varfirst,second,last:string[1];n:integer;begincount:=0;//移動之前count先賦值為0memo1.Lines.Clear;first:=trim(edit1.Text);second:=trim(edit2.Text);last:=trim(edit3.Text);n:=strtoint(edit4.Text);hanno(first[1],second[1],last[1],n)end;運(yùn)行結(jié)果如圖7-22所示?!纠?-14】編寫一個計(jì)算器程序。步驟如下:(1)添加加速按鈕SpeedButton1~SpeedButton16,添加編輯框Edit1,添加BitBtn組件BitBtn1和BitBtn2。2)調(diào)整這些組件的大小和位置,設(shè)置屬性,見表7-1所示。界面如圖7-23歲示。表7-1組件的屬性設(shè)置

(3)首先定義全局變量:implementation{$R*.dfm}varop:char;one,two,result:real;//定義全局變量(4)因?yàn)镾peedButton1~SpeedButton9的代碼類似,故同時選中數(shù)字按鈕“1”~“9”,即:SpeedButton1~SpeedButton9,在Events頁中選定OnClick事件,雙擊右邊空白欄,編寫事件過程TForm1.SpeedButton1Click。這樣SpeedButton1~SpeedButton9就共享了該事件過程。代碼如下:procedureTForm1.SpeedButton1Click(Sender:TObject);beginedit1.Text:=edit1.Text+(senderasTspeedbutton).caption;//所按鍵的Caption顯示在編輯框

ifop=#0//尚未輸入運(yùn)算符,即目前所按數(shù)字鍵是第一個操作數(shù)

thenbeginone:=strtofloat(edit1.text);//第1個操作數(shù)edit1.Text:=floattostr(one)//顯示在編輯框中endelsebegin//如果op<>#0,表示是第2個操作數(shù)two:=strtofloat(edit1.text);//第2個操作數(shù)edit1.Text:=floattostr(two)//顯示第2個操作數(shù)在編輯框end;end;編寫“0”的事件過程如下:procedureTForm1.SpeedButton10Click(Sender:TObject);beginifnot((pos('.',edit1.Text)=0)and(pos('0',edit1.Text)=1))//如果編輯框中無小數(shù)點(diǎn),且第一個字符是0,則不許繼續(xù)加入0字符

thenedit1.Text:=edit1.Text+SpeedButton10.Caption;//允許加入0字符

//將編輯框中的數(shù)字保存到操作數(shù)1或者操作數(shù)2ifop=#0//尚未輸入操作運(yùn)算符號

thenone:=strtofloat(edit1.text)//保留到第1個操作數(shù)中

elsetwo:=strtofloat(edit1.text)//保留到第2個操作數(shù)中end;編寫小數(shù)點(diǎn)SpeedButton11的事件過程,如下:procedureTForm1.SpeedButton11Click(Sender:TObject);beginifpos('.',edit1.Text)=0//無小數(shù)點(diǎn)則可以輸入小數(shù)點(diǎn)

thenedit1.Text:=edit1.Text+SpeedButton11.Caption;ifop=#0//如果是第1個操作數(shù)

thenone:=strtofloat(edit1.text)elsetwo:=strtofloat(edit1.text)//第2個操作數(shù)end;選擇“+”、“-”、“*”和“/”,即SpeedButton12~SpeedButton15,編寫共享的事件過程,如下:procedureTForm1.SpeedButton12Click(Sender:TObject);vars:string;begincaseopof/在按運(yùn)算符號之前,如果事先已經(jīng)按過運(yùn)算符則先運(yùn)算前面的運(yùn)算//并把結(jié)果作為當(dāng)前運(yùn)算的第1操作數(shù)

'+':result:=one+two;'-':result

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論