490 likes | 662 Views
第 4 章 结构化程序设计. 本章内容: 程序与程序文件 程序的基本结构 子程序和过程文件. 4.1 程序与程序文件. 4.1.1 程序的概念 程序:是能够完成一定任务的命令的有序集合。 程序文件:一组构成程序的命令被存放的文件称为程序文件或命令文件,建立好的程序可多次运行,也可根据需要修改和进一步完善。. 编写程序,显示数据表 XSDA.DBF 中性别为“男”的学生学号、姓名、出生日期。 下面是一个完整的 VFP 程序。 *程序文件名 lx4_1.prg SET TALK OFF && 关闭状态信息
E N D
第4章 结构化程序设计 本章内容: 程序与程序文件 程序的基本结构 子程序和过程文件
4.1 程序与程序文件 4.1.1程序的概念 程序:是能够完成一定任务的命令的有序集合。 程序文件:一组构成程序的命令被存放的文件称为程序文件或命令文件,建立好的程序可多次运行,也可根据需要修改和进一步完善。
编写程序,显示数据表XSDA.DBF中性别为“男”的学生学号、姓名、出生日期。下面是一个完整的VFP程序。编写程序,显示数据表XSDA.DBF中性别为“男”的学生学号、姓名、出生日期。下面是一个完整的VFP程序。 *程序文件名lx4_1.prg SET TALK OFF &&关闭状态信息 OPEN DATABASE JXGL &&打开数据库JXGL.DBC USE XSDA IN 0 &&D在当前最小工作区打开 XSDA.DBF CLEAR &&清屏 LIST 学号,姓名,出生日期 FOR 性别=”男” &&显示查询到的信息 CLOSE DATABASE &&关闭数据库 SET TALK ON &&打开状态信息 RETURN &&返回
此程序的几点说明: 1.命令分行 若命令一行写不下,则需分行书写,应在一行末尾输入分号,然后回车写续行。 2.命令注释 格式一:* <注释内容> 在要解释的命令前,又称行首注释。 格式二:&& <注释内容> 在要解释的命令后,又称行尾注释。 3.程序结尾的专用命令 RETUEN:置于程序末尾,返回到调用它的上级程序 CANCEL:使程序执行终止,并返回到命令窗口 QUIT:使程序终止执行,返回操作系统 4.SET TALK ON|OFF命令
4.1.2 程序文件的建立、修改与运行 在VFP中,一个程序文件就是一个ASCII文本文件,因而可用各类编辑工具来建立。 1.命令方式 (1)程序文件的建立和修改 命令格式:MODIFY COMMAND [<程序文件名>|?] 功能:打开一个编辑窗口,从中可以修改或创建程序文件。 (2) 程序的运行 命令格式:DO <文件名> 功能:运行已建立的程序文件。 说明:该命令除了可以从命令窗口调用程序外,还可以在程 序中使用,可以从一个程序调用子程序。如果文件不加扩展名,系统会假定它具有.PRG的扩展名。
2.通过项目管理器 (1)程序文件建立,操作步骤如下: 首先打开已建立的项目文件,选择“全部”选项卡中“代码”,并在“代码”中选择“程序”。
(2)程序文件的运行 在“管理项目器”的“代码”选项卡中的“程序”项中,选择程序,按下“运行”按钮,该程序的结果即显示于VFP的主窗口里。 3.菜单方式 (1)程序文件的建立 执行“文件”|“新建”命令,在对话框中选取择“程序”文件,出现程序编辑窗口,在程序编辑窗口逐条输入程序内容,保存程序文件。 (2)程序文件的运行 选择菜单“程序”中的“运行”命令,出现“运行”对话框,在“运行”对话框中选择程序文件后单击“运行”按钮。如要运行在程序编辑窗口的当前正在编辑的程序,可单击常用工具栏上的“运行”按钮。
4.1.3 程序设计中常用的输入输出命令 1.ACCEPT命令 格式:ACCEPT [<提示信息>] TO <内存变量名> 功能: 在程序执行过程中,将用户交互式输入的内容作为字符串赋值给指定内存变量。 说明: ①如果选用<字符表达式>,那么系统会首先显示该表达式的值,作为提示信息,并将输入的字符串赋值给<内存变量>。 ②该命令只能接收字符串,而不需加定界符,否则系统将把定界符作为字符串的一部分。 ③若不输入任何字符而直接按回车键,系统将把空串赋值给指定的内存变量。
【例4-2】编程从键盘输入学生姓名,在XSDA中查找并显示其内容。【例4-2】编程从键盘输入学生姓名,在XSDA中查找并显示其内容。 *程序文件名lx4_2.prg。 SET TALK OFF CLEAR USE XSDA ACCEPT "请输入要查找的学生名:" TO XM LOCATE FOR 姓名=XM DISP USE SET TALK ON RETURN
格式:INPUT[<字符表达式>] TO <内存变量> • 2.INPUT通用数据接收命令 说明: ①如果选用<字符表达式>,那么系统会首先显示该表达式的值,作为提示信息,并将输入的数据赋值给<内存变量>。 ②可以输入字符型、数值型、逻辑型、日期型等类型数据,而且可以是常量、变量或表达式等形式,按回车键结束输入。 ③输入非数值型数据要加定界符。如输入逻辑型常量时要用圆点定界(.T.)、输入日期型常量要用大括号{^2004-05-10}、输入字符型加””或’’等。
【例4-3】编写程序,查找指定籍贯和出生日期以后的学生。【例4-3】编写程序,查找指定籍贯和出生日期以后的学生。 *程序文件名lx4_3.prg SET TALK OFF CLEAR USE XSDA INPUT "请输入学生籍贯:" TO JG INPUT "请输入出生日期:" TO CSRQ DISP FOR 籍贯=JG AND 出生日期>CSRQ &&结果显示在查询窗口里 SET TALK ON USE RETURN
格式:WAIT[<字符表达式 >][TO <内存变量>] 3.WAIT命令 功能:显示信息并暂停程序执行,当按下任意键或单击鼠标后继续执行。 说明: ①字符表达式,系统将先显示字符表达式的值作为提示信息,并将输入的单字符赋值给<内存变量>。若不选用提示信息,则显示 “按任意键继续……”。 ②<内存变量>用来保存用户键入的单字符,其类型只能是字符型。若不选TO <内存变量>短语,键入的单字符不保留。 ③如果指定WINDOW子句,则会出现一个WAIT提示窗口,在窗口中显示提示信息。提示窗口一般定位于WINDOW子句。 ④TIMEOUT 选项指在中断WAIT 命令之前,等待键盘或鼠标输入的秒数,一旦超时就不再等待用户按键,自动向下执行。
【例4-4】用WAIT 命令在信息提示窗口显示:谢谢使用Visual FoxPro! WAIT “谢谢使用Visual FoxPro!” WINDOWS TIMEOUT 10
格式:@ <行, 列> [ SAY <字符表达式> ] [ GET <内存变量>] … READ 4.格式输入输出命令 功能:在指定的行、列位置显示或打印输出结果,也可接受数据的输入。 说明: ①行、列指定显示信息的起始位置(屏幕上的行、列号)。 ②SAY <字符表达式>在指定的起始位置显示信息。 ③GET <内存变量> 等待输入变量的值,GET子句的变量必须用READ 命令激活(即GET子句必须与READ 命令配合使用),在多个GET 子句后,仅用一个READ命令即可。
4.2 程序的基本结构 4.2.1顺序结构 顺序结构是最简单的程序结构,它按命令在程序中出现的先后次序依次执行。 【例4-1】到【例4-3】所给的程序均为顺序结构程序。
4.2.2 分支结构 分支结构是指程序流程发生了分支,程序执行时根据条件选择其中某一分支执行的程序结构。Visual FoxPro 6.0的分支结构按分支多少分为三类: 单分支 双分支 多分支
假 条件表达式 真 语句序列 ENDIF后面的语句 1. 单分支结构 格式: IF〈条件表达式〉 〈语句序列〉 ENDIF 图4-3 单分支结构流程图 功能:首先计算〈条件表达式〉的值,当〈条件表达式〉的值为真时,执行〈语句序列〉;否则,跳过“语句序列”,直接执行ENDIF后面的第一条语句。
【例4-5】 输入货物重量,计算该货物的托费,记费标准每公斤为0.1元,当超过50公斤后,超出数为0.2元。 *程序文件名LX4_5.prg INPUT “请输入货物重量:” TO w IF w<=50 f=w*0.1 &&货物重量没有超过50公斤时的计算公式 ENDIF IF w>50 f=50*0.1+(w-50)*0.2 &&货物重量超过50公斤时的公式 ENDIF ? “托运费为:”,f RETURN
真 假 条件表达式 语句序列B 语句序列A ENDIF后面的语句 2.双分支结构 格式: IF <条件表达式> <语句序列A> ELSE <语句序列B> ENDIF
例4-5也可以用双分支编程。 *程序文件名LX4_6.prg CLEAR INPUT “请输入货物重量:” TO w IF w<=50 f=w*0.1 &&货物重量没有超过50公斤时的计算公式 ELSE f=50*0.1+(w-50)*0.2 &&货物重量超过50公斤时的计算公式 ENDIF ? “托运费为:”,f RETURN
3.多分支结构 功能:依次判断各条件表达式,直至某条件表达式成立,就执行该CASE和下一个CASE之间的语句序列,然后转向执行ENDCASE后继语句。 说明: ①不管有几个CASE条件成立,只有最先成立的那个CASE条件的对应语句序列被执行。 ②若所有条件都不成立,如有OTHERWISE项,则执行该项后的语句序列n+1;若无OTHERWISE项,则直接执行ENDCASE后的语句。 ③DO CASE和ENDCASE必须成对出现,DO CASE 是本结构的入口,ENDCASE是本结构的出口。 格式:DO CASE CASE <条件1> <语句序列1> CASE <条件2> <语句序列2> … CASE <条件n> <语句序列n> [OTHERWISE <语句序列n+1>] ENDCASE
运行一个程序,随机输出一条信息: CLEAR AA=INT(RAND()*10) &&随机产生一个10以内的整数 DO CASE CASE AA=0 ? “这次产生的随机数是:0” CASE AA=1 ? “这次产生的随机数是:1” CASE AA=2 ? “这次产生的随机数是:2” CASE AA=3 ? “这次产生的随机数是:3” OTHERWISE ? “这次产生的随机数是:大于3!” ENDCASE
4.2.3循环结构 VFP支持循环结构的语句包括: DO WHILE-ENDDO FOR-ENDFOR/NEXT SCAN-ENDSCAN
假 条件 真 循环体 ENDDO后面的语句 1. DO WHILE-ENDDO语句 DO WHILE <条件> <语句序列1> [LOOP] <语句序列2> [EXIT] <语句序列3> ENDDO
【例4-9】计算S=1+2+3+···+10之和。 *程序文件名lx4_9.prg SET TALK OFF s=0 i=1 DO WHILE i<=10 s=s+i i=i+1 ENDDO ?"1~10的和为:", s SET TALK ON RETURN 用变量i作为计数器,计算循环次数,i可从1开始,每次循环增加1,直至10;用变量s作为累加器,初值为0
2.FOR-ENDFOR/NEXT语句 格式: FOR <循环变量>=<初值> TO <终值> [STEP <步长>] <循环体> ENDFOR|NEXT 功能:首先将初值赋给循环变量后,判断循环变量是否超过终值,若没超过,则执行循环体,循环变量增加一个步长值,再次判断循环变量是否超过终值以决定是否继续执行循环体;若超过,则直接执行ENDFOR的后续语句。
说明: ①循环变量没超过终值的2种情况: 若步长为正,则<循环变量>≤<终值> 若步长为负,则<循环变量>≥<终值> ②省略步长时,默认值为1。 ③初值、终值、步长均为数值表达式,仅在循环开始时计算一次,执行循环的过程中并不会改变。 ④循环变量值在循环体内可以改变,但会影响循环次数。 ⑤EXIT和LOOP命令可以出现在循环体内。执行LOOP命令时,结束本次循环,循环变量增加一个步长值,返回FOR循环头判断循环条件是否成立;执行EXIT命令时,程序跳出循环,执行ENDFOR后继语句。
【例4-11】用FOR……ENDFOR计算S=1+2+3+···+10。【例4-11】用FOR……ENDFOR计算S=1+2+3+···+10。 *程序文件名lx4_11.prg SET TALK OFF S=0 FOR I=1 TO 10 S=S+I ENDFOR ?"1~10的和为:",S SET TALK ON RETURN 用FOR……ENDFOR编写的累计计数程序,程序结构显得十分简洁、清晰。
3.SCAN-ENDSCAN语句 格式: SCAN [范围] [FOR<条件1>] [WHILE<条件2>] <循环体> ENDSCAN 功能:该语句为表扫描型循环语句,执行该语句时,记录指针在当前表的指定范围内自动、从上往下依次移到满足条件的记录上,并对每一条记录执行循环体内的命令,直到全部执行完退出循环;若表中没有满足条件的记录,则直接退出循环。
说明: ①范围:有ALL、NEXT n、Record n和REST。只有范围之内的记录才可能扫描到,SCAN 的默认范围ALL。 ②FOR<条件1>:针对范围之内所有满足条件的记录,执行循环体。 ③WHILE<条件2>:只有当前记录满足条件,才执行循环体,一旦遇到使条件表达式值为假的记录时,SCAN命令便终止,转向执行ENDSCAN后继语句。 ④EXIT、LOOP也可在循环体内使用,功能同DO WHILE-ENDDO和FOR-ENDFOR。
【例4-13】编写程序,从键盘上任意输入一个出生日期,显示XSDA表中比该出生日期迟的学生信息。【例4-13】编写程序,从键盘上任意输入一个出生日期,显示XSDA表中比该出生日期迟的学生信息。 *程序文件名lx4_13.prg SET TALK OFF CLEAR OPEN DATA JXGL USE XSDA GO TOP INPUT "任意输入一个出生日期:" TO csrq SCAN FOR 出生日期>csrq DISPLAY ENDSCAN CLOSE DATABASE SET TALK ON RETURN
语句嵌套 在一个循环中又包含另一个循环,称为循环嵌套。循环都可以相互嵌套。可以包含另一个循环的循环称为外循环,被包含的循环称为内循环,这种结构又称多重循环。 FOR DO WHILE FOR FOR …… ENDFOR ENDFOR ENDFORENDDO
结果为: i j 1 3 1 4 1 5 2 3 2 4 2 5 【例4-14】双重循环 *程序文件名lx4_14.prg CLEAR SET TALK OFF ?”i”,”j” FOR i=1 TO 2 FOR j=3 TO 5 ? i,j ENDFOR ENDFOR SET TALK ON RETURN
【例4-15】计算:s=1!+2!+3!+……+10! 程序分析: 用2层FOR……ENDFOR语句来实现。 内层循环用于计算每个数的阶乘即n!,外层循环控制n的值由1变化到10,每次循环n值增加1。 计算n!可参照前面计算1+2+……+10的编程思想方法,事先给定n值,用变量p存放n!的结果,令p的初值为1,在 FOR……ENDFOR语句的循环体中使用命令p=p*i,i为循环控制变量,每循环一次值加1,当i超过n时脱离内层循环。
s=0 FOR n=1 TO 10 p=1 FOR i=1 TO n p=p*i ENDFOR s=s+p ENDFOR ? s RETURN 结果为: 4037913
编程 1、输出斐波纳契(Fibonacci)数列的前20项,数列的规律是:第一、二个数是1,从第三个数起,每个数是前面两个数之和。 2、编一个程序求0~100之间(S=2+4+6+…+100)的偶数之和. 3、Y=1+1/2+1/3+ … +1/30
4.4 子程序和过程文件 • 程序设计时,常常有些运算或处理程序是相同的 • 可以将重复出现的或能单独使用的程序写成可供其他程序调用的独立程序段称为子程序,在VFP中也称为过程 • 在程序运行中,是通过主程序或主调程序去调用子程序或过程的,当子程序或过程运行完后,程序返回主调程序的调用处并执行下一条语句。
4.4.2过程的定义和调用 过程的定义格式: PROCEDURE∣FUNCTION <过程名> <语句序列> [RETURN [<表达式>]] [ENDPROC∣ENDFUNC]
过程的打开和关闭 (1)过程文件的打开: SET PROCEDURE TO <过程文件名表> (2)过程文件的关闭: SET PROCEDURE TO或 SET PROCEDURE TO 过程文件名1,过程文件名2……
过程的调用 格式1:使用DO 命令 DO<文件名>∣<过程名> 格式2:在名字后加一对小括号: <文件名>∣<过程名>() 在上面的两种格式里,如果模块是程序文件的代码,用<文件名>,否则用<过程名>。 格式2既可以作为命令使用(返回值被忽略),也可以作为函数出现在表达式里。在这里,<文件名>不能包含扩展名。
以一个独立的文件形式存在 【例4-19】求圆的面积和周长。 * 过程文件名sub.prg PROCEDURE pro1 &&过程名 S=3.14*r**2 RETURN PROCEDURE pro2 &&过程名 L=2*3.14*r RETURN * 主程序文件名lx4_19.prg CLEAR S=0 L=0 INPUT "请输入圆的半径:" TO r SET PROCEDURE TO sub.prg DO pro1 ?S DO pro2 ?L SET PROCEDURE TO RETURN
4.4.3参数传递 • 过程可以接收调用程序传递过来的参数,并能够对接收到的参数进行处理,从而大大提供模块程序功能设计的灵活性。 • 允许在调用命令和被调用过程中设置数量相同,类型一致的参数,按其排列顺序一一对应。 • 调用命令将一系列参数的值传送给被调用程序中的对应参数。 • 被调用程序运行结束时,再将相应参数的值(可能已被改变)返回。
调用模块程序的格式为: 格式1 :DO<文件名>∣<过程名>WITH<实参1>[,<实参2>,…] 格式2 :<文件名>∣<过程名><实参1>[,<实参2>,…] 说明: (1)参数可以是常量、变量和表达式 (2)采用格式1调用模块时如果实参是常量或一般形式的表达式,系统会计算出实参的值,并把它们赋值给相应的形参变量。这种情形称为按值传递。如果实参是变量,那么传递的是变量的地址。这种情形称为按引用传递。 (3)采用格式2调用模块程序时,默认情况下都以按值方式传递参数。如果实参是变量,可以通过命令SET UDFPARMS命令重新设置参数传递的方式。该命令的格式如下: SET UDFPARMS TO VALUE|REFERENCE
参数语句有以下格式: 语句格式: PARAMETERS 〈形参参数表〉 语句功能: 接受调用命令中相应参数的值,并在调用结束后返回对应参数的计算结果 说明: 参数表必须与调用命令中的参数相匹配。 参数语句与带参数调用语句必须配合使用,成对出现。
【例4-20】编写按值传递和按引用传递程序 do p3 with x1,(x2) ?"第三次:",x1,x2 store 100 to x1,x2 p3(x1,(x2)) ?"第四次:",x1,x2 procedure p3 parameters x1,x2 store x1+1 to x1 store x2+1 to x2 endproc *程序文件名lx4_20.prg clear store 100 to x1,x2 set udfparms to value &&格式2按值传递参数 do p3 with x1,(x2) ?"第一次:",x1,x2 store 100 to x1,x2 p3(x1,(x2)) ?"第二次:",x1,x2 set udfparms to reference &&格式2按引用传递参数 程序运行结果为: 第一次: 101 100 第二次: 100 100 第三次: 101 100 第四次: 101 100
4.4.4 变量的作用域 1.公共变量 格式: PUBLIC <内存变量表> 在任何模块中都可使用的变量称为公共变量。 2.私有变量 格式:PRIVATE <内存变量名表> 私有变量的作用域是建立它的模块以及其调用的下属各层模块。 3.局部变量 格式:LOCAL <内存变量表> 局部变量只能在定义它的模块中使用,该模块运行结束时局部变量自动释放。
【例4-21】通过程序了解变量的作用域 X=1 Y=3 Z=Z+3 ?"子程序中..." ? 'X=',X &&显示X=1 ? 'Y=',Y &&显示Y=3 ? 'Z=',Z &&显示Z=4 ENDPROC *程序文件名lx4_21.prg CLEAR RELEASE ALL &&清除所有用户定义的内存变量 PRIVATE Z Y=1 &&此处Y为私有变量 Z=1 DO Change ?"主程序中..." ? 'X=',X &&显示X=1,X为公共变量 ? 'Y=',Y &&显示Y=1, ? 'Z=',Z &&显示Z=4 Procedure Change PUBLIC X &&公共变量X,全局有效 LOCAL Y &&此处为Y局部变量,只在过程Change中有效。 结果如下: 子程序中... X= 1 Y= 3 Z= 4 主程序中... X= 1 Y= 1 Z= 4
编程练习: 利用参数传递和过程文件,求m!+n, m和n的值由用户输入。
第4章 结构化程序设计 本章结束