王秀娟 洪軍
摘要: VFP是基于數(shù)據(jù)庫(kù)管理和應(yīng)用程序開(kāi)發(fā)的高級(jí)語(yǔ)言。VFP中可以用子程序、過(guò)程、函數(shù)三種方式實(shí)現(xiàn)模塊程序設(shè)計(jì)。這三種方式功能相同,但格式、調(diào)用方式、數(shù)據(jù)傳遞方式又不盡相同;這三種方式可以相互轉(zhuǎn)換。學(xué)生在學(xué)習(xí)中常常不能確認(rèn)應(yīng)該采用哪種方式實(shí)現(xiàn)模塊功能。為此,詳細(xì)分析了三種方式的設(shè)計(jì)過(guò)程,以幫助學(xué)生理解并掌握這三種方式的結(jié)構(gòu)及其轉(zhuǎn)換格式,各種不同格式的調(diào)用方式,以及它們的用處和模塊的編程方法。
關(guān)鍵詞: 子程序; 過(guò)程; 函數(shù); 局部變量
中圖分類(lèi)號(hào):TP392文獻(xiàn)標(biāo)志碼:B 文章編號(hào):1006-8228(2012)11-44-04
Research and practice of three modularized program design methods in Visual FoxPro
Wang Xiujuan1, Hong Jun2
(1. School of electronics and computer science and technology, North University of China, Taiyuan, Shanxi 030051;
2. School of Software, North University of China)
Abstract: Visual FoxPro is an advanced language which is based on database management and application program development. There are three kinds of modularized programming method including subprogram, procedure and function. Though they have the same function, they are different in format program invocation, data transmission and can be transformed to each other which make the students unclear about which method they should use to design the module. A detailed analysis of the three methods and some examples are given to help the students to learn the structure, transition and invocation of the three methods and master the modularized program design easily.
Key words: subprogram; procedure; function; local variable
0 引言
VFP(Visual FoxPro)是一種關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),它不僅支持面向?qū)ο蟮目梢暬绦蛟O(shè)計(jì),還支持傳統(tǒng)的面向過(guò)程的程序設(shè)計(jì)。面向過(guò)程的程序設(shè)計(jì)方法要求將一個(gè)大的系統(tǒng)分解為多個(gè)模塊,用以實(shí)現(xiàn)功能的分解和代碼的重用。VFP中實(shí)現(xiàn)模塊的程序設(shè)計(jì)方法比較多,包括:子程序、過(guò)程、函數(shù)。下面舉例分析三種方式的異同。
1 三種設(shè)計(jì)方法詳解
1.1 子程序
在VFP中子程序的結(jié)構(gòu)和程序的結(jié)構(gòu)基本相同,通常使用MODIFY COMMAND命令單獨(dú)建立一個(gè)程序文件,以擴(kuò)展名.PRG保存成一個(gè)程序文件[1]。一般習(xí)慣在子程序的末尾加上RETURN命令返回調(diào)用處。調(diào)用子程序的格式為:DO 子程序文件名[WITH <參數(shù)表>]。
1.2 過(guò)程
VFP中按照過(guò)程是否單獨(dú)保存成程序文件將過(guò)程分為兩種:內(nèi)部過(guò)程和外部過(guò)程。內(nèi)部過(guò)程與主程序放在一個(gè)文件里,通常放在主程序文件的后面;外部過(guò)程單獨(dú)保存成一個(gè)程序文件,優(yōu)點(diǎn)是不依附于主程序,可以被多個(gè)程序共享[2]。
內(nèi)部過(guò)程格式:
PROCEDURE <過(guò)程名>
[PARAMETERS <形式參數(shù)表>]
<命令組>
RETURN|ENDPRO
調(diào)用格式:DO 過(guò)程名 WITH <參數(shù)表>
下面舉例說(shuō)明內(nèi)部過(guò)程和外部過(guò)程之間的區(qū)別,編寫(xiě)程序?qū)崿F(xiàn)輸出任意兩個(gè)數(shù)值之間的所有素?cái)?shù),在過(guò)程中判斷單個(gè)數(shù)是否素?cái)?shù)。
例1:內(nèi)部過(guò)程。
*MAIN.PRG文件代碼如下:
INPUT TO X1
INPUT TO X2
FOR M=X1 TO X2
FLAG=.T.
DO PRIME WITH M,F(xiàn)LAG
IF FLAG
?M
ENDIF
ENDFOR
CANCEL
PROCEDURE PRIME
PARAMETERS N,F(xiàn)LAG1
K=INT(SQRT(N))
J=2
DO WHILE J<=K .AND. FLAG1
IF MOD(N,J)=0
FLAG1=.F.
ENDIF
J=J+1
ENDDO
RETURN
例2:外部過(guò)程。
*MAIN.PRG文件代碼如下:
INPUT TO X1
INPUT TO X2
FOR M=X1 TO X2
FLAG=.T.
DO P1.PRG WITH M,F(xiàn)LAG
IF FLAG
?M
ENDIF
ENDFOR
CANCEL
*外部過(guò)程文件P1.PRG代碼如下:
PARAMETERS N,F(xiàn)LAG1
K=INT(SQRT(N))
J=2
DO WHILE J<=K .AND. FLAG1
IF MOD(N,J)=0
FLAG1=.F.
ENDIF
J=J+1
ENDDO
RETURN
在例1中將內(nèi)部過(guò)程PRIME和主程序放在同一個(gè)文件中,并放在主程序的后面,程序運(yùn)行時(shí)從主程序開(kāi)始,當(dāng)執(zhí)行到命令DO PRIME WITH M,F(xiàn)LAG時(shí),轉(zhuǎn)去執(zhí)行過(guò)程PRIME,其中PRIME是過(guò)程名。用外部過(guò)程實(shí)現(xiàn)時(shí),主程序和外部過(guò)程分別存放在兩個(gè)程序文件中,主程序文件調(diào)用時(shí)使用命令DO P1.PRG WITH M,F(xiàn)LAG,其中P1.PRG是外部過(guò)程保存的文件名,另外在外部過(guò)程文件中不需要使用“PROCEDURE <過(guò)程名>”語(yǔ)句定義過(guò)程名,因?yàn)檫^(guò)程名不起作用,調(diào)用時(shí)使用的是文件名。
此外,如果在調(diào)用過(guò)程時(shí)需要返回?cái)?shù)據(jù)給主調(diào)程序,此時(shí)不能通過(guò)RETURN命令返回,因?yàn)槭褂谩癉O”命令調(diào)用過(guò)程時(shí),過(guò)程中的“RETURN”命令不能返回?cái)?shù)據(jù)(即使使用“RETURN表達(dá)式”形式,也不能將表達(dá)式的結(jié)果返回,此時(shí)的表達(dá)式不起作用)[3]。這時(shí)可以通過(guò)傳地址的方式來(lái)實(shí)現(xiàn)將過(guò)程的運(yùn)行結(jié)果傳回調(diào)用處。在程序中使用變量“FLAG”作為過(guò)程調(diào)用的返回值,過(guò)程調(diào)用前“FLAG=.T.”(即假定被判定數(shù)據(jù)為素?cái)?shù)),調(diào)用過(guò)程時(shí)將實(shí)參FLAG的值傳遞給形參FLAG1(此時(shí)FLAG1=.T.),在調(diào)用過(guò)程中判定數(shù)據(jù)是否能整除,若能整除則修改變量“FLAG1”的值為“.F.”,若所有的除數(shù)都不能整除則FLAG1的值不變。調(diào)用過(guò)程結(jié)束時(shí)將形參N的值傳回給實(shí)參M,將形參FLAG1的值傳回給實(shí)參FLAG,即通過(guò)傳地址的方式在調(diào)用過(guò)程中實(shí)現(xiàn)將運(yùn)算數(shù)據(jù)返回調(diào)用處。
1.3 函數(shù)
VFP中函數(shù)有兩種類(lèi)型:庫(kù)函數(shù)和自定義函數(shù)。其中庫(kù)函數(shù)是VFP系統(tǒng)為用戶提供的內(nèi)部函數(shù),用以實(shí)現(xiàn)一些常用的功能,用戶可以直接調(diào)用。自定義函數(shù)是用戶根據(jù)需要自己編寫(xiě)的函數(shù)(即自定義函數(shù))[3]。
自定義函數(shù)格式:
[FUNCTION <函數(shù)名>]
[PARAMETERS <參數(shù)表>]
<命令組>
RETURN [<表達(dá)式>]
函數(shù)的調(diào)用形式是:
<函數(shù)名>(<自變量表>)
例3:將例1用過(guò)程編寫(xiě)的求素?cái)?shù)的程序改寫(xiě)成用函數(shù)來(lái)實(shí)現(xiàn)。
INPUT TO X1
INPUT TO X2
FOR M=X1 TO X2
IF PRIME(M)
? M
ENDIF
ENDFOR
CANCEL
FUNCTION PRIME
PARAMETERS N
FLAG=.T.
K=INT(SQRT(N))
J=2
DO WHILE J<=K .AND. FLAG
IF MOD(N,J)=0
FLAG=.F.
ENDIF
J=J+1
ENDDO
RETURN FLAG
在例3中用“RETURN FLAG”命令給函數(shù)返回一個(gè)值,事實(shí)上在函數(shù)調(diào)用過(guò)程中通過(guò)RETURN命令最多只能返回一個(gè)值到函數(shù)調(diào)用處。若想返回多個(gè)結(jié)果只是使用RETURN命令是無(wú)法實(shí)現(xiàn)的。
為了對(duì)比子程序、函數(shù)、過(guò)程三種結(jié)構(gòu)的異同,現(xiàn)將上述程序用子程序的方式來(lái)編寫(xiě),如下所示。
例4:
*MAIN.PRG文件代碼如下:
INPUT TO X1
INPUT TO X2
FOR M=X1 TO X2
FLAG=.T.
DO P2
IF FLAG
?M
ENDIF
ENDFOR
CANCEL
*子程序文件P2.PRG代碼如下:
K=INT(SQRT(M))
J=2
DO WHILE J<=K .AND. FLAG
IF MOD(M,J)=0
FLAG=.F.
ENDIF
J=J+1
ENDDO
RETURN
在例4中利用局部變量的特點(diǎn),局部變量的作用域是在本級(jí)和下級(jí)程序中都可以使用[4],因此在子程序P2中判斷數(shù)據(jù)M是否是素?cái)?shù),然后修改局部變量FLAG的值,調(diào)用子程序“DO P2”后,判斷變量“FLAG”的值,返回為真時(shí),M是素?cái)?shù)。
2 三種方式調(diào)用形式探討
從以上的4個(gè)小程序可以看出,在VFP中通過(guò)子程序、函數(shù)、過(guò)程都可以實(shí)現(xiàn)模塊的編寫(xiě),三種方式功能相同。雖然在VFP中模塊的實(shí)現(xiàn)方式分成這樣的三種方式,但實(shí)際上這三種形式也不是涇渭分明的,也就是說(shuō)無(wú)論它們的編寫(xiě)格式和調(diào)用格式都不是固定不變的。上面介紹的格式是人們通常習(xí)慣的一種編寫(xiě)和調(diào)用格式。對(duì)于子程序、函數(shù)、過(guò)程都可以采用 “<函數(shù)名>(<自變量表>)”或“DO 過(guò)程名 WITH <參數(shù)表>” 的調(diào)用形式。例如在調(diào)用子程序時(shí)也可以使用函數(shù)的調(diào)用形式即 <函數(shù)名>(<自變量表>),同樣調(diào)用函數(shù)時(shí)也可用DO <文件名>的形式來(lái)執(zhí)行。下面以求圓柱體的體積為例,對(duì)比在子程序、過(guò)程、函數(shù)中采用不同的調(diào)用方式時(shí),源程序的異同。
例5:
*子程序的一般調(diào)用格式,MAIN.PRG程序代碼如下:
INPUT TO R
INPUT TO H
V=0
DO P3.PRG
?V
*子程序P3.PRG代碼如下:
V=PI()*R^2*H
RETURN
例5是采用一般的子程序格式編寫(xiě)和調(diào)用的,將這個(gè)程序改成使用函數(shù)格式調(diào)用,修改如下:
例6:
*子程序采用函數(shù)的調(diào)用格式,MAIN.PRG程序代碼如下:
INPUT TO R
INPUT TO H
V=0
P3(R,H)&& DO P3 WITH R,H
?V
*子程序P3.PRG代碼如下:
PARA R,H
V=PI()*R^2*H
RETURN
程序調(diào)試運(yùn)行后,驗(yàn)證結(jié)果是正確的。說(shuō)明子程序的調(diào)用也可使用函數(shù)的調(diào)用格式,但此時(shí)需要注意的是在子程序中必須要有“PARAMETERS”語(yǔ)句,因?yàn)樵诤瘮?shù)調(diào)用過(guò)程中要將實(shí)參的值傳遞給對(duì)應(yīng)的形參,實(shí)參和形參必須一一對(duì)應(yīng),所以PARAMETERS語(yǔ)句不能缺少。在上述程序中也可將“P3(R,H)”命令改寫(xiě)成“DO P3 WITH R,H”,此時(shí)也存在實(shí)參和形參之間的數(shù)據(jù)傳遞,而且從外觀上看更像是外部過(guò)程形式了。
再將例6改成用函數(shù)實(shí)現(xiàn)求圓柱體的體積,代碼修改如下:
例7:
*函數(shù)一般調(diào)用格式:
INPUT TO R
INPUT TO H
?CYLINDER(R,H)
FUNCTION CYLINDER
PARA R,H
V=PI()*R^2*H
RETURN V
例8:例7中的函數(shù)不變,將函數(shù)調(diào)用方式該為DO命令調(diào)用。
INPUT TO R
INPUT TO H
V=0
DO CYLINDER WITH R,H
?V
FUNCTION CYLINDER
PARA R,H
V=PI()*R^2*H
RETURN V
對(duì)比例7和例8兩個(gè)程序,對(duì)于函數(shù)的調(diào)用也可使用“DO 函數(shù)名 WITH 參數(shù)表列”形式,但調(diào)用過(guò)程結(jié)束時(shí),不能通過(guò)RETURN命令來(lái)返回運(yùn)算結(jié)果,此時(shí)RETURN后的表達(dá)式不起作用。在該程序中采用了局部變量V,在函數(shù)調(diào)用過(guò)程中修改變量V的值來(lái)實(shí)現(xiàn)數(shù)據(jù)的傳遞。從這個(gè)例子中看出,雖然編寫(xiě)的是函數(shù),但是在調(diào)用時(shí)用的是“DO”命令,此種調(diào)用方法不能通過(guò)RETURN命令來(lái)返回運(yùn)算結(jié)果。
例9:將該程序用過(guò)程形式實(shí)現(xiàn),修改如下:
*過(guò)程一般調(diào)用格式
INPUT TO R
INPUT TO H
V=0
DO CYLINDER WITH R,H
?V
CANCEL
PROCEDURE CYLINDER
PARA R,H
V=PI()*R^2*H
RETURN
例10:將例9的過(guò)程調(diào)用方式改為“過(guò)程名(實(shí)參表列)”形式。
INPUT TO R
INPUT TO H
?CYLINDER(R,H)
PROCEDURE CYLINDER
PARA R,H
V=PI()*R^2*H
RETURN V
程序調(diào)試運(yùn)行后,驗(yàn)證結(jié)果也是正確的。對(duì)比上述的兩個(gè)程序,也可使用“過(guò)程名(實(shí)參表列)”形式調(diào)用過(guò)程,而且采用這種形式調(diào)用過(guò)程時(shí)還可以通過(guò)RETURN命令返回結(jié)果。
從以上程序的驗(yàn)證結(jié)果來(lái)看,在編寫(xiě)函數(shù)和過(guò)程時(shí),不管是用“FUNCTION”還是“PROCEDURE”都是一樣的,關(guān)鍵是看調(diào)用時(shí)使用的是“DO”命令還是“函數(shù)名(實(shí)參表列)”。這兩種形式調(diào)用時(shí)都實(shí)現(xiàn)實(shí)參到形參數(shù)據(jù)的傳遞[5]。若采用“函數(shù)名(實(shí)參表列)”形式調(diào)用,調(diào)用結(jié)束后通過(guò)“RETURN”命令可以返回一個(gè)結(jié)果給調(diào)用處;若采用“DO”命令調(diào)用函數(shù)或過(guò)程,因?yàn)闊o(wú)法通過(guò)“RETURN”命令返回結(jié)果,此時(shí)可以采用全局變量或局部變量的方式來(lái)實(shí)現(xiàn)在上下級(jí)程序之間數(shù)據(jù)的傳遞,或是在“DO 過(guò)程名 WITH <參數(shù)表>”中通過(guò)在“參數(shù)表”中多增加參數(shù)方式來(lái)實(shí)現(xiàn)(即將調(diào)用函數(shù)或過(guò)程需傳回的數(shù)據(jù)另外設(shè)成一個(gè)參數(shù)),在函數(shù)或過(guò)程調(diào)用結(jié)束后通過(guò)將形參的值再傳遞給實(shí)參,比如例1中判斷一個(gè)數(shù)是否素?cái)?shù)的內(nèi)部過(guò)程的實(shí)現(xiàn)方式就屬于這種。
同理,子程序也是一樣的,只是將過(guò)程名或函數(shù)名變成了程序文件名,調(diào)用時(shí)同樣可以采用兩種形式。
3 結(jié)束語(yǔ)
子程序、函數(shù)、過(guò)程本質(zhì)上是一樣的,在調(diào)用時(shí)都是通過(guò)變量的作用域和實(shí)參—形參數(shù)據(jù)傳遞兩種方式實(shí)現(xiàn)數(shù)據(jù)的傳遞的。調(diào)用時(shí)可以使用“DO”命令或“函數(shù)名(實(shí)參表列)”兩種形式。當(dāng)調(diào)用形式不同時(shí),程序也略有不同。經(jīng)過(guò)以上分析,作者認(rèn)為雖然很多書(shū)中把模塊化的程序設(shè)計(jì)方式分成子程序、過(guò)程、函數(shù)三種,我們?nèi)匀豢梢园阉鼈兌伎闯墒亲映绦颍ㄒ驗(yàn)樗鼈兌疾荒軌騿为?dú)運(yùn)行)。這樣,子程序就包括兩種:一種是子程序單獨(dú)保存在一個(gè)程序文件中(即外部子程序),另一種是子程序和程序在同一個(gè)文件中(即內(nèi)部子程序),此時(shí)需要給子程序一個(gè)標(biāo)志(即過(guò)程名或函數(shù)名)。
外部子程序單獨(dú)在一個(gè)文件,此時(shí)子程序可以和普通程序相同結(jié)構(gòu),也可包含PARAMETERS子句。外部子程序格式和調(diào)用方式如表1所示。
表1外部子程序格式及其調(diào)用方式
[[格式\&調(diào)用方式\&普通子程序\&DO\&PARAMETERS\&DO 子程序 WITH <實(shí)參表列>
子程序(實(shí)參表列)\&]]
內(nèi)部子程序和主程序在同一個(gè)文件,子程序必須放在主程序的后面。內(nèi)部子程序格式和調(diào)用方式如表2所示。
表2內(nèi)部子程序格式及其調(diào)用方式
[[\&調(diào)用方式\&PROCEDURE子程序名\&DO 子程序 WITH <實(shí)參表列>
子程序(實(shí)參表列)\&FUNCTION 子程序名\&DO 子程序 WITH <實(shí)參表列>
子程序(實(shí)參表列)\&]
]
VFP以其本身的優(yōu)勢(shì),被許多高校作為一門(mén)計(jì)算機(jī)基礎(chǔ)課程。筆者在多年從事VFP教學(xué)的過(guò)程中,不斷嘗試總結(jié),最終發(fā)現(xiàn),在講述模塊的程序設(shè)計(jì)方法時(shí),采用以上的方法進(jìn)行講解,有利于學(xué)生掌握模塊的含義及其編寫(xiě),達(dá)到事半功倍的效果。此外,VFP的教學(xué)還需要深入探討。
參考文獻(xiàn):
[1] 劉衛(wèi)國(guó).Visual FoxPro程序設(shè)計(jì)教程(第2版)[M].北京郵電大學(xué)出版
社,2005.
[2] 柳青,劉順來(lái).Visual FoxPro程序設(shè)計(jì)教程(第2版)[M].高等教育出版
社,2009.
[3] 潘曉南.Visual FoxPro數(shù)據(jù)庫(kù)應(yīng)用技術(shù)[M].中國(guó)鐵道出版社,2004.
[4] 劉麗.Visual FoxPro程序設(shè)計(jì)[M].中國(guó)鐵道出版社,2005.
[5] 張瑩.Visual FoxPro數(shù)據(jù)庫(kù)與程序設(shè)計(jì)教程[M].機(jī)械工業(yè)出版社,
2007.