1、第3章结构化程序设计,内容提要:,引言:,前面各章都是以交互方式,即在命令窗口中逐条输入命令或通过使用菜单来进行操作的。这种方式虽然很方便,但是也有一些弊端,因此我们还可以把有关的操作命令组织在一起,存放到一个文件中,当发出调用该文件的命令后,Visual FoxPro就会自动地依次执行该文件中的命令,直至全部命令执行完毕,这就是Visual FoxPro的程序工作方式,它是实际应用中主要的工作方式。,3.1程序设计概述,什么叫程序设计? 使用计算机解决实际问题,通常是先要对问题进行分析并建立数学模型,然后考虑数据的组织方式和算法,并用某一种程序设计语言编写程序,最后调试程序,使之运行后能产生
2、预期的结果。这个过程称为程序设计。,程序的控制结构:,顺序结构,选择结构,循环结构,程序文件的建立与执行,建立或修改程序文件:(1) 命令方式 :MODIFY COMMAND 文件名?MODIFY FILE 文件名? 菜单方式 :,编写与执行程序 :,程序的编写:打开文本编辑窗口后,就可以一条一条地输入命令。当程序建立或修改完毕后,可用Ctrl+W键存盘,退出编辑窗口。要修改程序文件,选择“文件”菜单中的“打开”命令打开文件即可。 程序的执行: 命令方式 : DO 文件名 菜单方式:打开“程序”菜单,选择“运行”,然后在“运行”对话框中输入被执行的程序文件名即可,3.2顺序结构程序设计,程序文
3、件中的辅助命令 :1. 程序注释命令 :NOTE* 注释& 注释 2. 常用状态设置命令 : 设置会话状态命令 :SET TALK ONOFF 设置打印状态命令 : SET PRINT ONOFF 设置屏幕状态命令 :SET CONSOLE ONOFF 设置默认驱动器和目录命令 : SET DEFAULT TO 盘符:路径,程序文件中的辅助命令:,输入输出命令 : 字符串接收命令 :ACCEPT 提示信息 TO 内存变量 任意数据输入命令: INPUT 提示信息 TO 内存变量 单个字符接收命令 : WAIT 提示信息 TO 内存变量以上三条命令都是显示提示信息,等待用户从键盘输入数据后按回车
4、将数据赋给指定内存变量.不同在于接受的数据类型不一样.,格式输入输出命令,格式输入命令 行,列 SAY 提示信息 GET 变量 READSAVECYCLETIMEOUT等待时间此命令用READ命令来激活当前所有的GET变量,显示并允许修改变量的值。 格式输出命令 : SAYFUNCTION PICTURE格式符 此命令在指定坐标位置按格式输出表达式的值。其中行,列指定了输出的位置。,顺序结构 :,什么是顺序结构?顺序结构程序按照语句排列的先后顺序,一条接一条地依次执行,它是程序中最基本的结构。顺序结构是最简单的一种结构,关键是要掌握程序文件的建立、执行、修改的方法。下面我们通过两个例题来了解顺
5、序结构。,顺序结构示例:,例3.1据输入的人口基数与年平均增长率,计算20年后的人口总数。,SET TALK OFF INPUT 人口基数: TO a INPUT 年平均增长率: TO b p=a*(1+b)*20 ? 20年后人口数:+STR(p,10) SET TALK ON,开始,输入a,b,计算,输出结果,结束,顺序结构示例:,例3.2编写一个根据半径求圆的面积的程序,SET TALK OFF CLEAR INPUT “请输入圆的半径:” TO r S=PI()*r*r ?S SET TALK ON,3.3选择结构程序设计,在Visual FoxPro中,提供两种实现选择结构的语句:I
6、F语句和DO CASE语句,分别用于实现双分支选择结构和多分支选择结构。,双分支选择结构,语句格式:IF 条件 命令组1ELSE 命令组2ENDIF,IF语句执行时,如果条件成立,就执行命令组1,命令组1执行完成后就转到ENDIF之后的命令。如果条件不成立,当有ELSE子句时,执行命令组2,命令组2执行完成后转去执行ENDIF之后的命令;当没有ELSE子句时,则直接转到ENDIF之后的命令。,使用IF语句需要注意的:,(1) 选择语句只能在程序中使用,正因为只能在程序中使用,一般称之为语句,而不叫做命令。以后其他语句也是这样。 (2) IF,ELSE,ENDIF必须各占一行。每一个IF都必须有
7、一个ENDIF与其对应,即IF和ENDIF必须成对出现。 (3)条件可以为关系表达式、逻辑表达式或其他逻辑量。(4)命令组1或命令组2中可以包含IF语句,即IF语句可以嵌套。,简单IF语句示例:,编写一个程序,实现下面功能:任意输入一个整数,判断它是奇数还是偶数.,简单IF语句示例:,SET TALK OFF Input 请输入一个整数: to x If mod(x,2)=0 ? “这个数是一个偶数。” Else ? “这个数是一个奇数。” Endif return,分支结构主体,判断某一年是否是闰年.,解:根据闰年年号能被4整除且不能被100整除,或能 被400整除进行判断。程序设计如下:
8、,INPUT 请输入年份: TO yIF (y/4=int(y/4) .and. y/100int(y/100) or y/400=int(y/400)? y,年是闰年。ELSE? y,年不是闰年。ENDIF,IF语句嵌套示例:,例3.4硅谷公司员工的工资计算方法如下。 (1) 工作时数超过 120小时者,超过部分加发15%。 (2) 工作时数低于60小时者,扣除300元。 (3) 其余按每小时84元计发。试编程按输入的工号和该号员工的工时数,计算该员工的应发工资。 分析: 这个题目中实际上员工的工资是分三种情况发放,但是我们暂时没有学到多分支结构,所以我们利用现在所学的双分支结构将其分为两种
9、情况,然后再继续划分。,IF语句嵌套示例:,SET TALK OFFCLEARACCEPT 工号: TO ghINPUT 工时: TO gsIF gs120gz=GS*84+(gs-120)*84*0.15ELSEIF gs60gz=gs*84ELSEgz=gs*84-300ENDIFENDIF? gh+号职工应发工资:+STR(gz,8,2)SET TALK ON,多分支选择结构:,DO CASE CASE 条件1 命令组1 CASE 条件2 命令组2 CASE 条件n 命令组n OTHERWISE 命令组n+1 ENDCASE,多分支选择结构:,执行过程: 执行DO CASE语句时,依次判
10、断各条件是否满足,若条件满足,就执行该条件后的命令组,直到遇到下一个CASE、OTHERWISE或ENDCASE。命令组执行后不再判断其他条件,而转向执行ENDCASE后面的第一条命令。 使用注意点: (1) DO CASE、CASE、OTHERWISE、ENDCASE必须各占一行。每一个DO CASE都必须有一个ENDCASE与其对应。 (2) 可以为关系表达式、逻辑表达式或其他逻辑量。,【例3.8】编写程序将学生百分制成绩转换为等级制成绩。转换规则如表3.3所示,SET TALK OFF CLEAR INPUT “请输入学生成绩:” TO score IF score70IF score
11、60grade=”不及格”ELSEgrade=”及格”ENDIF ELSE,IF score 80grade=”中”ELSEIF score 90grade=”良”ELSEgrade=”优”ENDIFENDIF ENDIF,思考:试着用多分支选择结构完成例题3.4,Set talk off clear Input 工时: to gsDO CASE CASE gs120gz=GS*84+(gs-120)*84*0.15 CASE gs60 gz=gs*84 otherwise gz=gs*84-300 ENDCASE ? 职工应发工资:+STR(gz,8,2),思考: 这段程序中两个case条件
12、能不能换位置?,3.4循环结构程序设计,什么时候要用到循环? 当一条或者一段命令需要被重复执行很多次时,我们考虑用循环解决。循环结构是一种重要的程序结构。Visual FoxPro提供了DO WHILE、FOR、SCAN等3种循环语句。,DO WHILE循环,DO WHILE命令组 EXIT LOOP ENDDO,执行过程: 当给定的条件满足时,执行DO WHILE和ENDDO之间的命令组。命令组执行完毕后,程序自动返回到DO WHILE语句,再一次判断DO WHILE语句中的条件。如果条件仍然满足,则再执行一遍命令组,如果条件不满足,则结束循环,转去执行ENDDO之后的命令。,语句格式,语句
13、格式,DO WHILE 称为循环说明语句,语句格式,DO WHILE,循环体,ENDDO,ENDDO的作用是使循环回到循环说明语句,语句格式,DO WHILE,循环体,ENDDO,DO WHILE 和 ENDDO语句必须配对使用,语句格式,DO WHILE,循环体,ENDDO,语句格式,DO WHILE,循环体,ENDDO,当值为假时,退出循环,执行,ENDDO后面的语句,其值为真时,执行循环体,条件表达式,循环体,ENDDO 之后的语句,.T.,.F.,条件循环执行流程,条件循环执行流程,条件循环应用举例,例1:在屏幕上换行显示字符串OK20次,SET TALK OFF,SET TALK O
14、N,RETURN,CLEAR,例1:在屏幕上换行显示字符串OK20次,i=1,?OK,i=i+1,ENDDO,DO WHILE,SET TALK OFF,SET TALK ON,RETURN,CLEAR,i=20,&设置循环变量初值,&修改循环变量,在以循环变量作为循环控制参数的条件循环中,循环体内一定要有修改循环变量的语句,否则就会出现死循环,DO WHILE 语句之前一定要有设置循环变量初 值的语句,注意,求自然数1至4的和。,SET TALK OFF,S=0,&指定以循环次数作判断条件,S=S+i,&修改循环变量,?S,&输出求和的结果,SET TALK ON,RETURN,&设置循环变
15、量的初值,S=0,i=1,1=4,S=1,i=2,.T.,2=4,S=3,i=3,3=4,S=6,i=4,4=4,S=10,i=5,i=4,.F.,10,SET TALK OFF S=0 i=1 DO WHILE i=4S=S+ii=i+1 ENDDO ?S SET TALK ON RETURN,让我们来画出程序的流程图:,求自然数1至4的和。,SET TALK OFF,S=0,i=1,INPUT 请输入N的值: TO N,DO WHILE i=4,S=S+i,i=i+1,ENDDO,?S,SET TALK ON,RETURN,若求自然数1至N的和呢?,推 广 1,改为: DO WHILE i
16、=N,求自然数1至N的和。,SET TALK OFF,S=0,i=1,INPUT 请输入N的值: TO N,DO WHILE i=N,S=S+i,i=i+1,ENDDO,?S,SET TALK ON,RETURN,若求自然数1至N的积呢?,推 广 2,改为: S=1,改为: S=S*i,循环中loop语句与exit语句的作用,LOOP语句,DO WHILE ,ENDDO,LOOP,若执行循环体时遇到LOOP,则直接返回DO语句,测试条件式以决定是否继续循环,循 环 体,循环中loop语句与exit语句的作用,LOOP语句,DO WHILE ,ENDDO,IF ,ENDIF,LOOP一般放在IF
17、条件语句中并可出现在循环体内任何位置,阅读程序,并说出程序的结果,LOOP,ENDIF,程序结果,2,3,4,5,6,程序结果,2,4,5,6,IF i=3,EXIT语句,DO WHILE ,ENDDO,循 环 体,ENDDO后面的语句,EXIT,若执行循环体时遇到EXIT,则直接跳出循环,执行ENDDO后面的语句,循环中loop语句与exit语句的作用,2.2 EXIT语句,DO WHILE ,ENDDO,IF ,ENDIF,EXIT一般放在IF条件语句中可出现在循环体内任何位置,循环中loop语句与exit语句的作用,S=1*2*3*当S800时退出,求大于800的第一个s值,程序结果为:
18、 42,IF S800,EXIT,ENDIF,课堂练习,求1,100内所有能被3或被5整除的数的个数,IF MOD(i,3)=0 .OR. MOD(i,5)=0,N=N+1,ENDIF,N=0,&定义一个变量表示个数,并初始化,&总个数增加1,SET TALK OFF,? 满足条件的数的个数为,N,SET TALK ON,RETURN,? i,&显示满足条件的这个数,FOR循环的格式和功能,1.1 语句基本格式,语句基本格式,FOR 称为循环说明语句,X 称为循环变量,A 为循环初值 B 为循环终值, C 为循环步长,语句基本格式,FOR X=A TO B,STEP C,循环体,ENDFOR,
19、ENDFOR的作用是使循环变量按C增值,回到循环说明语句,语句基本格式,FOR循环,使用注意: (1) FOR,ENDFORNEXT必须各占一行,且它们必须成对出现。 (2) 循环变量可以是一个内存变量或数组元素。如果在FORENDFOR之间改变循环变量的值,将影响循环执行的次数。 (3)、和均为数值型表达式。如果省略STEP子句,则默认步长值是1。 (4) 退出循环后,循环变量的值等于最后一次循环时的值为加上步长值。 (5) LOOP语句和EXIT语句的功能与前面的DO WHILE循环语句相同。,X超越终值B,循环体,ENDFOR 之后的语句,.F.,.T.,循环执行流程,X按步长C增值,循
20、环变量X赋初值A,FOR循环示例:,计算1+2+3+100的和:,Set talk off S=0 I=1 Do while I=100 S=S+I I=I+1 Enddo ? S,Set talk off S=0 For I=1 to 100 step 1 S=S+I Endfor ? S,用FOR循环实现1+3+5+99?,FOR循环的应用,有时候我们利用循环结构将所有的可能的情况全部列出来,一一测试,判断是否满足条件,从而求出满足条件的数,这种方法称为穷举法。穷举对于计算机来说是很容易实现的。 例如,找出所有的水仙花数:例3.8所谓水仙花数是指一个三位整数,其各位数字的立方和等于该数本身
21、(如153=13+53+33)。求所有的水仙花数。,FOR循环的应用,分析:这道题目要求我们找出所有水仙花数,该从哪里入手呢? 水仙花数肯定都是三位的正整数,那么,我们利用循环把所有的三位正整数全部列出来,一个个去找。 首先,三位正整数肯定在100到999之间,先利用FOR循环实现M从100到999之间变化。 For m=100 to 999 接下来,关键求出M所对应的个位十位以及百位数。 a=INT(m/100)&百位数字 b=INT(MOD(m,100)/10) &十位数字 c=m%10 &个位数字,FOR循环的应用,CLEAR FOR m=100 TO 999 a=INT(m/100)
22、b=INT(MOD(m,100)/10) c=m%10 IF m=a3+b3+c3 ? m ENDIF,如果是要求水仙花的个数呢?,CLEAR I=0 FOR m=100 TO 999 a=INT(m/100) b=INT(MOD(m,100)/10) c=m%10 IF m=a3+b3+c3 I=I+1 ENDIF ?I,循环的嵌套,循环的嵌套是指循环结构的循环体中又包含循环结构,又称为多重循环。在Visual FoxPro中,循环嵌套的层数不限,但内层循环必须完全嵌套在外层循环之中,层次分明,不允许交叉,否则会造成逻辑上的混乱。,循环的嵌套,以下交叉情形不允许出现:,3.5程序的模块化,结
23、构化程序设计方法要求将一个大的系统分解为若干个子系统,每个子系统构成一个程序模块。程序的模块化在具体实现上就是采用子程序技术,具体形式有3种:子程序、过程和函数。,子程序,在Visual FoxPro程序文件中,可以通过DO命令调用另一个程序文件,此时,被调用的程序文件就称为子程序。子程序的结构与一般的程序文件一样,而且也可以用MODIFY COMMAND命令来建立、修改和存盘,扩展名也默认为.prg。子程序与其他程序文件的惟一区别是其末尾或返回处必须有返回语句。 命令格式: RETURNTO MASTER|TO|,子程序的调用,子程序调用命令与主程序执行命令相同,其格式都是: DOWITH主
24、程序可以调用子程序,子程序还可以调用另外的子程序,这就是子程序的嵌套调用。实际上,子程序和主程序都是相对的,任何一个程序可以调用其他程序,也可以被其他程序调用。每个被调用程序的末尾或返回处都要加上RETURN命令。,子程序的调用需要注意的地方,如果在某一个子程序的RETURN命令中使用TO MASTER短语,则从此子程序直接返回到第一级主程序,其间子程序DO命令以下的命令均不执行。,自定义函数,前面已经用到了许多Visual FoxPro的内部函数,除直接调用内部函数外,Visual FoxPro还允许用户根据需要定义进行某种运算或操作的函数,这些函数被称为自定义函数。函数其实也是程序的一种,
25、所以他的扩展名也是.prg。,自定义函数的格式是: FUNCTION 函数名 PARAMETERS 参数表命令组RETURN 表达式,自定义函数的调用,函数名(自变量表),例3.16定义一个判断n是否是素数的函数,然后调用该函数求21000内的全部素数。,素数也叫质数,它大于1,且除了1和它本身以外,不能被其他任何整数整除。为了判断某数n是否为素数,一个最简单的办法是用2,3,4,5,n-1这些数逐个去除n,看能否除尽,如果全都除不尽,则n是素数;否则,只要其中一个数除尽了,则n不是素数。为了减少整除的次数,提高运行效率,除到n即可。,判断n是否是素数的函数,主程序 FOR m=2 TO 10
26、00 IF prime(m)? m ENDIF ENDFOR CANCEL,*prime.prg PARAMETERS n flag=.T. k=INT(SQRT(n)C j=2 DO WHILE j=k .AND. flagIF MOD(n,j)=0flag=.F.ENDIFj=j+1 ENDDO RETURN flag,过程与过程文件,过程的一般格式是: PROCEDURE 过程名 PARAMETERS 参数表命令组 RETURN,函数其实也是过程的一种,函数是带返回值的过程。 所以过程的使用方法跟函数一样。,过程文件,一个过程可以以文件形式单独存在,也可以将多个过程合并到一个文件中,这个
27、文件称为过程文件。在过程文件中,每个过程仍然是独立的,可以单独调用。由于过程文件是将许多过程集中起来以一个文件的形式存储在磁盘中的,所以当打开一个过程文件时,该过程文件中的所有过程即同时被打开;关闭一个过程文件时,过程文件中的所有过程也同时被关闭,从而大大减少了访问磁盘的次数,提高了程序运行速度。过程文件也是程序文件,同其他程序文件一样,可以用MODIFY COMMAND命令或其他文字编辑软件进行编辑。,过程文件的打开与关闭,打开过程文件的命令格式是:SET PROCEDURE TO 过程文件名 关闭过程文件可以使用下列两条命令:SET PROCEDURE TOCLOSE PROCEDURE,
28、内存变量的作用域,一个大的应用系统通常由许多子程序组成,这些子程序必然会用到许多内存变量,根据变量的作用范围不同,可将内存变量分为全局内存变量和局部内存变量。,全局内存变量 : 全局内存变量是指在上、下各级程序中都有效的内存变量。全局变量就像在一个程序中定义的变量一样,可以任意改变和引用,当程序执行完后,其值仍然保存。若要清除这种变量,必须用RELEASE命令。,全局内存变量,命令格式1: PUBLIC 内存变量表ALLALL LINK 通配符ALL EXCEPT 通配符 命令格式2: PUBLIC ARRAY 数组名(下标上界1,下标上界2),数组名(下标上界1,下标上界2),这两种格式的命
29、令分别定义全局内存变量或数组。,局部内存变量,局部内存变量只能在定义它的程序及其下级程序中使用,一旦定义它的程序运行结束,它便自动被清除。也就是说,在某一级程序中定义的局部变量,不能进入其上级程序使用,但可以在其下级程序中使用,而且当在下级程序中改变了该变量的值时,在返回本级程序时被改变的值仍然保存,本级程序可以继续使用改变后的变量值。,注意:如没有特殊定义,则在命令窗口创建的内存变量为全局的,在程序中创建的内存变量为局部变量。,隐藏内存变量,隐藏内存变量只能在定义它的程序,一旦定义它的程序运行结束,它便自动被清除。也就是说,在某一级程序中定义的局部变量,不能进入其上级程序使用,也不能在其下级
30、程序中使用。,隐藏内存变量的命令格式是:PRIVATE 内存变量表ALLALL LIKE 通配符ALL EXCEPT 通配符,调用子程序时的数据传递,调用子程序时,调用程序要把数据传递给子程序,子程序也可能把数据传回到调用程序,因此在调用子程序过程中,必然要考虑调用程序和被调用程序之间的数据是如何传递的,调用子程序时的数据传递可以通过两种方式来解决。 1.利用变量的作用域实现数据传递 2.利用参数实现数据传递,3.6程序调试,程序调试就是确定程序出错的位置,然后加以改正,一直到满足预定的设计要求为止。程序调试往往是先分模块调试,当各模块都调试通过以后,再联合起来进行调试,通过联调后,便可试运行
31、,试运行无误即可投入正常使用。 调试器窗口的使用: 选择“工具”菜单中的“调试器”命令或在命令窗口输入DEBUG命令,系统打开调试器窗口。在Visual FoxPro调试器窗口中,选择“窗口”菜单中的相应命令可有选择地打开5个子窗口:跟踪、监视、局部、调用堆栈和调试输出。,跟踪窗口用于显示正在调试执行的程序文件。 跟踪窗口左端的灰色区域会显示某些符号,常见的符号及其意义如下: (1) :指向调试中正在执行的代码行。 (2) :断点。可以在某些代码行处设置断点,当程序执行到该代码行时,程序执行中断。,跟踪窗口,监视窗口,监视窗口用于监视指定表达式在程序调试执行过程中的取值变化情况。 要设置一个监
32、视表达式,可单击监视窗口中的“监视”文本框,然后输入表达式的内容,按回车键后表达式便加入文本框下方的列表框中。当程序调试执行时,列表框内将显示所有监视表达式的名称、当前值及类型。在监视窗口中可以设置表达式类型的断点。,局部窗口,局部窗口用于显示模块程序(程序、过程和方法程序)中的内存变量(简单变量、数组、对象),显示它们的名称、当前取值和类型。用鼠标右键单击局部窗口,然后在弹出的快捷菜单中选择“公共”、“局部”、“常用”或“对象”等命令,可以控制在列表框内显示的变量种类。,调用堆栈窗口,调用堆栈窗口用于显示当前处于执行状态的程序、过程或方法程序。若正在执行的程序是一个子程序,那么主程序和子程序
33、的名称都会显示在该窗口中。 (1) 调用顺序序号:序号小的模块程序处于上层,是调用程序。序号大的模块程序处于下层,是被调用程序,序号最大的模块程序也就是当前正在执行的模块程序。(2) 当前行指示器():指向当前正在执行的行所在的模块程序。,调试输出窗口,可以在模块程序中设置一些DEBUGOUT命令,其格式是:DEBUGOUT 表达式当模块程序调试执行到此命令时,会计算出表达式的值,并将计算结果送入调试输出窗口。为了区别于DEBUG命令,命令词DEBUGOUT至少要写出6个字母。,设置断点,类型1:在定位处中断。可以指定一个代码行,当程序调试/执行到该代码时就中断程序运行。 类型2:如果表达式值为真则在定位处中断。指定一个代码行以及一个表达式,当程序调试执行到该行代码时,如果表达式的值为真,就中断程序运行。 类型3:当表达式值为真时中断。可以指定一个表达式,在程序调试/执行过程中,当该表达式值为真时,就中断程序运行。 类型4:当表达式值改变时中断。指定一个表达式,在程序调试/执行过程中,当该表达式值改变时,就中断程序运行。,“调试”菜单,在调试器窗口中的“调试”菜单包含执行程序、选择执行方式、终止程序执行、修改程序以及调整程序执行速度等命令。,