APP下载

VFP中三种模块化程序设计方法的研究与实践

2012-04-29王秀娟洪军

计算机时代 2012年11期
关键词:子程序函数过程

王秀娟 洪军

摘要: VFP是基于数据库管理和应用程序开发的高级语言。VFP中可以用子程序、过程、函数三种方式实现模块程序设计。这三种方式功能相同,但格式、调用方式、数据传递方式又不尽相同;这三种方式可以相互转换。学生在学习中常常不能确认应该采用哪种方式实现模块功能。为此,详细分析了三种方式的设计过程,以帮助学生理解并掌握这三种方式的结构及其转换格式,各种不同格式的调用方式,以及它们的用处和模块的编程方法。

关键词: 子程序; 过程; 函数; 局部变量

中图分类号:TP392文献标志码:B 文章编号: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)是一种关系型数据库管理系统,它不仅支持面向对象的可视化程序设计,还支持传统的面向过程的程序设计。面向过程的程序设计方法要求将一个大的系统分解为多个模块,用以实现功能的分解和代码的重用。VFP中实现模块的程序设计方法比较多,包括:子程序、过程、函数。下面举例分析三种方式的异同。

1 三种设计方法详解

1.1 子程序

在VFP中子程序的结构和程序的结构基本相同,通常使用MODIFY COMMAND命令单独建立一个程序文件,以扩展名.PRG保存成一个程序文件[1]。一般习惯在子程序的末尾加上RETURN命令返回调用处。调用子程序的格式为:DO 子程序文件名[WITH <参数表>]。

1.2 过程

VFP中按照过程是否单独保存成程序文件将过程分为两种:内部过程和外部过程。内部过程与主程序放在一个文件里,通常放在主程序文件的后面;外部过程单独保存成一个程序文件,优点是不依附于主程序,可以被多个程序共享[2]。

内部过程格式:

PROCEDURE <过程名>

[PARAMETERS <形式参数表>]

<命令组>

RETURN|ENDPRO

调用格式:DO 过程名 WITH <参数表>

下面举例说明内部过程和外部过程之间的区别,编写程序实现输出任意两个数值之间的所有素数,在过程中判断单个数是否素数。

例1:内部过程。

*MAIN.PRG文件代码如下:

INPUT TO X1

INPUT TO X2

FOR M=X1 TO X2

FLAG=.T.

DO PRIME WITH M,FLAG

IF FLAG

?M

ENDIF

ENDFOR

CANCEL

PROCEDURE PRIME

PARAMETERS N,FLAG1

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:外部过程。

*MAIN.PRG文件代码如下:

INPUT TO X1

INPUT TO X2

FOR M=X1 TO X2

FLAG=.T.

DO P1.PRG WITH M,FLAG

IF FLAG

?M

ENDIF

ENDFOR

CANCEL

*外部过程文件P1.PRG代码如下:

PARAMETERS N,FLAG1

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中将内部过程PRIME和主程序放在同一个文件中,并放在主程序的后面,程序运行时从主程序开始,当执行到命令DO PRIME WITH M,FLAG时,转去执行过程PRIME,其中PRIME是过程名。用外部过程实现时,主程序和外部过程分别存放在两个程序文件中,主程序文件调用时使用命令DO P1.PRG WITH M,FLAG,其中P1.PRG是外部过程保存的文件名,另外在外部过程文件中不需要使用“PROCEDURE <过程名>”语句定义过程名,因为过程名不起作用,调用时使用的是文件名。

此外,如果在调用过程时需要返回数据给主调程序,此时不能通过RETURN命令返回,因为使用“DO”命令调用过程时,过程中的“RETURN”命令不能返回数据(即使使用“RETURN表达式”形式,也不能将表达式的结果返回,此时的表达式不起作用)[3]。这时可以通过传地址的方式来实现将过程的运行结果传回调用处。在程序中使用变量“FLAG”作为过程调用的返回值,过程调用前“FLAG=.T.”(即假定被判定数据为素数),调用过程时将实参FLAG的值传递给形参FLAG1(此时FLAG1=.T.),在调用过程中判定数据是否能整除,若能整除则修改变量“FLAG1”的值为“.F.”,若所有的除数都不能整除则FLAG1的值不变。调用过程结束时将形参N的值传回给实参M,将形参FLAG1的值传回给实参FLAG,即通过传地址的方式在调用过程中实现将运算数据返回调用处。

1.3 函数

VFP中函数有两种类型:库函数和自定义函数。其中库函数是VFP系统为用户提供的内部函数,用以实现一些常用的功能,用户可以直接调用。自定义函数是用户根据需要自己编写的函数(即自定义函数)[3]。

自定义函数格式:

[FUNCTION <函数名>]

[PARAMETERS <参数表>]

<命令组>

RETURN [<表达式>]

函数的调用形式是:

<函数名>(<自变量表>)

例3:将例1用过程编写的求素数的程序改写成用函数来实现。

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”命令给函数返回一个值,事实上在函数调用过程中通过RETURN命令最多只能返回一个值到函数调用处。若想返回多个结果只是使用RETURN命令是无法实现的。

为了对比子程序、函数、过程三种结构的异同,现将上述程序用子程序的方式来编写,如下所示。

例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中利用局部变量的特点,局部变量的作用域是在本级和下级程序中都可以使用[4],因此在子程序P2中判断数据M是否是素数,然后修改局部变量FLAG的值,调用子程序“DO P2”后,判断变量“FLAG”的值,返回为真时,M是素数。

2 三种方式调用形式探讨

从以上的4个小程序可以看出,在VFP中通过子程序、函数、过程都可以实现模块的编写,三种方式功能相同。虽然在VFP中模块的实现方式分成这样的三种方式,但实际上这三种形式也不是泾渭分明的,也就是说无论它们的编写格式和调用格式都不是固定不变的。上面介绍的格式是人们通常习惯的一种编写和调用格式。对于子程序、函数、过程都可以采用 “<函数名>(<自变量表>)”或“DO 过程名 WITH <参数表>” 的调用形式。例如在调用子程序时也可以使用函数的调用形式即 <函数名>(<自变量表>),同样调用函数时也可用DO <文件名>的形式来执行。下面以求圆柱体的体积为例,对比在子程序、过程、函数中采用不同的调用方式时,源程序的异同。

例5:

*子程序的一般调用格式,MAIN.PRG程序代码如下:

INPUT TO R

INPUT TO H

V=0

DO P3.PRG

?V

*子程序P3.PRG代码如下:

V=PI()*R^2*H

RETURN

例5是采用一般的子程序格式编写和调用的,将这个程序改成使用函数格式调用,修改如下:

例6:

*子程序采用函数的调用格式,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

程序调试运行后,验证结果是正确的。说明子程序的调用也可使用函数的调用格式,但此时需要注意的是在子程序中必须要有“PARAMETERS”语句,因为在函数调用过程中要将实参的值传递给对应的形参,实参和形参必须一一对应,所以PARAMETERS语句不能缺少。在上述程序中也可将“P3(R,H)”命令改写成“DO P3 WITH R,H”,此时也存在实参和形参之间的数据传递,而且从外观上看更像是外部过程形式了。

再将例6改成用函数实现求圆柱体的体积,代码修改如下:

例7:

*函数一般调用格式:

INPUT TO R

INPUT TO H

?CYLINDER(R,H)

FUNCTION CYLINDER

PARA R,H

V=PI()*R^2*H

RETURN V

例8:例7中的函数不变,将函数调用方式该为DO命令调用。

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

对比例7和例8两个程序,对于函数的调用也可使用“DO 函数名 WITH 参数表列”形式,但调用过程结束时,不能通过RETURN命令来返回运算结果,此时RETURN后的表达式不起作用。在该程序中采用了局部变量V,在函数调用过程中修改变量V的值来实现数据的传递。从这个例子中看出,虽然编写的是函数,但是在调用时用的是“DO”命令,此种调用方法不能通过RETURN命令来返回运算结果。

例9:将该程序用过程形式实现,修改如下:

*过程一般调用格式

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的过程调用方式改为“过程名(实参表列)”形式。

INPUT TO R

INPUT TO H

?CYLINDER(R,H)

PROCEDURE CYLINDER

PARA R,H

V=PI()*R^2*H

RETURN V

程序调试运行后,验证结果也是正确的。对比上述的两个程序,也可使用“过程名(实参表列)”形式调用过程,而且采用这种形式调用过程时还可以通过RETURN命令返回结果。

从以上程序的验证结果来看,在编写函数和过程时,不管是用“FUNCTION”还是“PROCEDURE”都是一样的,关键是看调用时使用的是“DO”命令还是“函数名(实参表列)”。这两种形式调用时都实现实参到形参数据的传递[5]。若采用“函数名(实参表列)”形式调用,调用结束后通过“RETURN”命令可以返回一个结果给调用处;若采用“DO”命令调用函数或过程,因为无法通过“RETURN”命令返回结果,此时可以采用全局变量或局部变量的方式来实现在上下级程序之间数据的传递,或是在“DO 过程名 WITH <参数表>”中通过在“参数表”中多增加参数方式来实现(即将调用函数或过程需传回的数据另外设成一个参数),在函数或过程调用结束后通过将形参的值再传递给实参,比如例1中判断一个数是否素数的内部过程的实现方式就属于这种。

同理,子程序也是一样的,只是将过程名或函数名变成了程序文件名,调用时同样可以采用两种形式。

3 结束语

子程序、函数、过程本质上是一样的,在调用时都是通过变量的作用域和实参—形参数据传递两种方式实现数据的传递的。调用时可以使用“DO”命令或“函数名(实参表列)”两种形式。当调用形式不同时,程序也略有不同。经过以上分析,作者认为虽然很多书中把模块化的程序设计方式分成子程序、过程、函数三种,我们仍然可以把它们都看成是子程序(因为它们都不能够单独运行)。这样,子程序就包括两种:一种是子程序单独保存在一个程序文件中(即外部子程序),另一种是子程序和程序在同一个文件中(即内部子程序),此时需要给子程序一个标志(即过程名或函数名)。

外部子程序单独在一个文件,此时子程序可以和普通程序相同结构,也可包含PARAMETERS子句。外部子程序格式和调用方式如表1所示。

表1外部子程序格式及其调用方式

[[格式\&调用方式\&普通子程序\&DO\&PARAMETERS\&DO 子程序 WITH <实参表列>

子程序(实参表列)\&]]

内部子程序和主程序在同一个文件,子程序必须放在主程序的后面。内部子程序格式和调用方式如表2所示。

表2内部子程序格式及其调用方式

[[\&调用方式\&PROCEDURE子程序名\&DO 子程序 WITH <实参表列>

子程序(实参表列)\&FUNCTION 子程序名\&DO 子程序 WITH <实参表列>

子程序(实参表列)\&]

]

VFP以其本身的优势,被许多高校作为一门计算机基础课程。笔者在多年从事VFP教学的过程中,不断尝试总结,最终发现,在讲述模块的程序设计方法时,采用以上的方法进行讲解,有利于学生掌握模块的含义及其编写,达到事半功倍的效果。此外,VFP的教学还需要深入探讨。

参考文献:

[1] 刘卫国.Visual FoxPro程序设计教程(第2版)[M].北京邮电大学出版

社,2005.

[2] 柳青,刘顺来.Visual FoxPro程序设计教程(第2版)[M].高等教育出版

社,2009.

[3] 潘晓南.Visual FoxPro数据库应用技术[M].中国铁道出版社,2004.

[4] 刘丽.Visual FoxPro程序设计[M].中国铁道出版社,2005.

[5] 张莹.Visual FoxPro数据库与程序设计教程[M].机械工业出版社,

2007.

猜你喜欢

子程序函数过程
二次函数
第3讲 “函数”复习精讲
二次函数
函数备考精讲
描写具体 再现过程
临终是个怎样的过程
在这个学习的过程中收获最大的是哪些,为什么?
浅谈子程序在数控车编程中的应用
圆满的过程
子程序在数控车加工槽中的应用探索