1、第7章 程序设计基础,掌握程序文件的概念及创建方法 熟悉简单的交互式输入输出命令的使用 熟悉应用程序的调试与执行方法 掌握顺序、选择和循环这三种结构的程序设计方法 掌握过程与过程调用的方法,基本要求与基本知识点,教学重点与难点,程序文件的建立及修改 简单的交互式输入输出命令 程序设计的三种基本结构:顺序、选择和循环结构 变量的类别及作用域 过程调用的方式及调用中参数的传递,主要介绍面向过程设计中用到的顺序语句、分支 结构、循环结构等语句的使用及格式,用其组成 应用程序,完成一定的程序功能。,程序是能够完成一定任务的命令的有序集合。 程序的特点: 1.程序控制流模式,由顺序、选择、循环三种基本结
2、构构成,每一个基本结构可以包含一条或多条语句。 2.面向对象可视化的结构程序模块,每个模块也是由程序控制流组成的。,7.1 程序与程序文件,1) 命令注释:提高程序的可读性以note或*开头的代码行为注释行,在命令 行后也可以加上注释,该注释以&符号开头 标识 2)命令分行:用分号完成行的延续 3)是否显示命令的执行结果用set talk on|off完成设置 4) Visual FoxPro命令或语句中的关键字在一般情况下只输入前4个字符就有效。,程序编写时注意的问题,1.建立: 项目管理器 “文件”“新建”“程序” modify command 或用菜单方式 在程序编辑窗口中编辑程序代码
3、存盘退出:Ctrl+W或Ctrl+End或按“关闭”按钮 取消当前编辑的代码:Ctrl+Esc 源程序文件的扩展名为.prg,执行程序时会自动编译,生成与源文件主文件名相同、扩展名为.fxp的文件。,7.1.2 建立、修改与执行程序,说明: 1)是要建立或修改的文件名。若省略文件名,则打开名为“程序1”的程序编辑窗口。 2) 系统默认扩展名为.prg。 3)在中可含通配符“*”和“?”,这时与之相匹配的每个文件会出现在不同的编辑窗口中。,4) 如使用“?”,则显示“打开”对话框,用户可在此框中输入要建立的新的程序文件或选择已存在的程序文件。 5)如使用NOEDIT选项,则将此程序设置为只读,可
4、以查看或将其复制到剪贴板,但不能修改。,do 程序名或程序菜单中的do program 说明:当执行程序文件时,文件中包含的命令、语句将被依次执行,直到所有的命令、语句被执行完毕,或者执行到以下命令为止: CANCEL终止程序运行,清除所有的程序中设置的变量,返回命令窗口。,2.运行, DO转去执行另一程序,然后返回本程序。 RETURN结束当前程序的执行,返回到调用它的上一级程序,若无上级程序则返回到命令窗口。 QUIT退出VFP系统,返回到操作系统。,当用DO命令执行程序文件时,如果没有指定文件的扩展名,系统将按下列顺序:Visual FoxPro执行文件(扩展名为.exe)、Visual
5、 FoxPro应用程序文件(扩展名为.app)、编译文件(扩展名为.fxp)、源程序文件(扩展名为.prg)。3.修改程序:同建立的方法,1.accept命令接受用户输入的信息,作为字符串赋给相应的变量,不须另加定界符,否则作为字符串内容。格式:accept to 例如:accept “请输入学生姓名:” to xmaccept “请输入文件名:” to filenameuse &filename注意:不输入直接回车,变量内容为空串。,7.1.3 基本的输入输出命令,WAIT TO WINDOW AT, TIMEOUT 接受单个字符,一般用于等待用户键入某一字符信息 例如:wait 说明: 1
6、)若无选项,显示默认提示“按任意键继续”,等待用户按任意键或单击鼠标。,2.wait命令,2)若包含TO 项,则将键盘的输入以字符形式存入所指定的内存变量。如输入的是回车键、不可打印的字符、组合键或单击鼠标,则将一个空串保存在内存变量中。 若包含WINDOW选项,则将显示在Visual FoxPro主窗口右上角的系统消息窗口中。 若包含AT,选项,则在主窗口中指定消息窗口的位置。, TIMEOUT选项必须是命令中的最后一个子句,用于规定等待键盘输入的时间限制,可为小数。一旦超时就不再等待用户按键,程序自动往下执行。 例: ?“欢迎使用Visual FoxPro!“ WAIT ?“Visual
7、FoxPro!“ WAIT WINDOW ?“FoxPro!“ CANCEL,接受用户输入的各类表达式的值,赋给相应的变量,可以接受C、D、N、L型数据,C、D、L型输入时要加上定界符 格式:input to 说明: 1) 可以是字符型变量,也可以是字符串,如果是字符串,必须用单引号、双引号或方括号括起。 2) 输入的数据可以是常量、变量,也可以为一般的表达式。表达式可以是数值型、字符型、逻辑型或日期型。但不能不输入任何内容直接按回车键。,3.input命令,3) 的数据类型由从键盘上所输入的表达式的类型所决定。输入字符串时必须加定界符,输入逻辑型常量时要用圆点定界,如.T.、.F.,输入日期
8、时间型常量时要用大括号 例如:input “请输入学生姓名:” to xm输入时:“李昆”input “请输入学生总分:” to ZF输入时:560input “继续输入吗?(Y/N):” to confirm 输入时:.Y.或.N.或.T.或.F., 格式化输入命令 say 表达式GET READ 【功能】在指定的位置显示提示信息并允许输入一个常量,当执行READ时将常量赋给指定的变量。 【说明】命令中的可以是内存变量和字段变量。,4. 定位输出命令, 格式化输出语句。 【格式】 SAY PICTURE 【功能】在指定的,按指定的格式输出。 【说明】用来限定数据输出的类型、长度及格式。 表7
9、.1给出常用格式描述符的含义。,【例】 CLEAR xm=“ “ USE d:ssstud 10,10 SAY “请输入姓名:“ GET xm READ xm=ALLTRIM(xm) LOCATE FOR 姓名=xm 13,10 SAY “学号“ PICTURE “xxxxxxx“ 13,18 SAY 学号 PICTURE “999999999“ 14,10 SAY “姓名“ PICTURE “xxxxxxx“ 14,18 SAY 姓名 PICTURE “xxxxxxx“ CANCEL,顺序结构:自上而下的执行方向 例:打开学生表,查询姓名为所输入的姓名值的记录,并显示 7.2.1 分支结构程
10、序设计 根据条件的成立与否,决定程序的走向。 1. 单分支结构:if Endif注:条件表达式为关系表达式、逻辑表达式或产生逻辑结果值的函数等。,7.2 结构化程序设计,A=10 If a=10s=0 Endif S=1 ?s,Input to a If a=0if a0s=0elses=1endif Else s=-1 Endif S=1 ?s,程序运行后的结果分别是什么?,if elseEndif 3. if语句可以嵌套 If if elseEndif elseendif,例子 USE e:zwssstud Accept “请输入姓名” to xm Locate for 姓名=xm If
11、found()disp Else?”没有此学生” endif,2. 双分支结构,【例】在stud表中,查找姓名为“牛耕耘”的记录,如果找到,给该记录加上删除标记,没有找到则显示提示信息“查无此人”。 Open Database e:zwssstudent Use stud Locate For 姓名=“牛耕耘“ If .Not. Eof() Delete Else 2,30 Say “查无此人“ EndIf Browse Close Database Return,Do casecase .case otherwise Endcase 例:根据学生成绩表中的成绩信息输出其成绩等级。 90分以上
12、为优秀 80分以上为良好,4. 多分支结构,【例】设计程序,输入任意一个百分制成绩,按优秀、良好、及格和不及格四个等级输出结果。具体为:0至59分为不及格,60至74分为及格,75至89分为良好,90至100分为优秀。CLEAR INPUT “请输入成绩(1100):“ TO fs DO CASE CASE fs100 .OR. fs89 ?“优秀“ CASE fs74 ?“良好“ CASE fs59 ?“及格“ OTHERWISE ?“不及格“ ENDCASE CANCEL,完成重复操作的程序结构。 设计循环时,需设计循环变量的初始值、循环的入口条件、循环的出口条件。,7.2.2 循环结构,
13、1. 当型循环当条件满足时执行循环体do while loopexitenddo Loop:强制进入下次循环,后面 的循环体不执行 Exit:强制退出循环,7.2.2 循环结构,循环体,Set talk off S=0 I=1 Input “n=?” to n Do while s=ns=s+II=I+1 Enddo ?s Set talk on,若输入N值为5,则最后S的值为?,CLOSE DATABASE A=0 USE STOCK GO TOP DO WHILE .NOT.EOF()IF 单价10 &假设表中有单价字段a=a+1Endif SKIP ENDDO ?a USE,Dime k
14、(2,3) I=1 Clear Do while I=2j=1do while j=3k(I,j)=I*j?k(I,j)j=j+1enddoI=I+1? enddo,2 3 4 6,【例】按姓名对stud表进行查询,要求所查人员不存在时有提示信息。 Open Database d:ssstudent Use stud Clear Do While .t.Accept “请输入所查询人员的姓名:“ To xmLocate For 姓名=xmIf .Not. Eof()DispElse? “查无此人!“EndIfWait “继续查询吗?(YN)“ TO jxIf jx “Y“ .And. jx “
15、 y“ExitEndIf EndDo Close Database Cancel,等价于 Ucase(jx)Y,将表中工龄20的每人增加60元,工龄20年的每人增加100元,请将程序补充完整。 Set talk off Use geqk Do while _if 工龄20replace 工资 with 工资+60elsereplace 工资 with 工资+100endif_ Enddo use Set talk on return,For = to step loopexitEndfor/next功能: 先将赋给, 并记住和,然后按变化的方向,用的值与比较,如的值超过,则跳出循环,执行End
16、ForNext的后续语句;否则执行循环体语句,当执行到EndForNext时,的值与相加后,重新返回for语句与比较,直到的值超过为止。,2. 固定次数的循环结构,说明: 如果省略Step 项,则默认为1。 、和均为数值型表达式。 Exit与Loop命令同样可以出现在循环语句的循环体内。循环体中可包含Visual FoxPro的任何语句,如有循环语句,则为循环的嵌套。 如为正,为递增循环,超过的意思是比大;如为负,则为递减循环,超过的意思是比小。,clear For I=15 to 5 step 3if I%3=0I=I-1endifI=I-2?I Endfor 最后I的值为多少?循环了多少次
17、?,例:计算自然对数e的近似值(n为20)e=1+1/1!+1/2!+1/n!store 1 to t,e for I=1 to 20t=t*Ie=e+1/tendfor 例:请填空完成计算p=1+1/(2X2)+1/(3X3)+1/(10X10)的程序。p=0n=1do while _p=p+1/(n*n)_enddo?preturn,【例】设计程序,对stud表进行操作,逐条输出1988年出生的学生信息。Open Database d:ssstudent Use d:ss stud Clear Count FOR YEAR(出生日期)=1988 To cs Locate for Year(
18、出生日期)=1988 *Go Top For i=1 To csDisplayWait Window TimeOut 2Continue EndFor Close Database Cancel,【例】设计程序,对stud表进行操作,逐条输出1988年出生的学生信息。Open Database d:ssstudent Use d:ss stud Clear Locate for Year(出生日期)=1988 Do while not eof()DisplayWait Window TimeOut 2Continue EndDo Close Database Cancel,【例】在屏幕上显示九
19、九乘法表。Set talk off Clear For j=1 to 9?str(j,2)+)for k=1 to j?str(j*k,6)endfor? Endfor return,例:任意输入一个数,判断是否素数并输出相应结果。 Input “请输入一个数:” to n For I=2 to sqrt(n)if n mod I=0p=1exitendif Endfor If p=0?n,”是素数“ Else ?str(n,3)+”不是素数“ endif,Input 请输入一个数: to n p=0 For I=2 to sqrt(n)if mod(n,I)=0p=1exitendif En
20、dfor If p=0?n,是素数 Else ?str(n,3)+不是素数 endif,do whil .t.,accep “是否继续输入并判断(Y/N)?“ to x if upper(x)=Yloop elseexit endif,enddo,考虑:分别用do while 和for 循环实现 1.求1100之间所有偶数的平方和并输出结果。 2.统计学生表中男生和女生的人数并输出。,专门用于处理数据表中的记录数据 格式: Scan for while Endscan功能:从首记录开始对当前表中满足条件的记录进行扫描处理。,3. 表扫描循环结构,Use stud Scan do case ca
21、se 性别=女sexw=sexw+1case 性别=男sexm=sexm+1endcase endscan ?“女生人数:”+str(sexw) ? “男生人数:”,sexm,3. 表扫描循环结构,【例】对stud表进行操作,显示所有班级为“06广告设计”记录学生的“姓名”、“班级”信息。 Open Database d:ssstudent Use stud Clear 2,30 say “姓 名“ 2,42 say “班 级“ rc=1 SCAN all For 班级=“06广告设计“ 2+rc,30 say 姓名 2+rc,40 say 班级 rc=rc+1 EndScan Close D
22、atabase Cancel,7.3.1 模块程序的定义和调用 能够完成某种特定功能的独立程序称为过程或子程序。 1. 定义过程 ProcedureFunction Return EndProcEndFunc 功能:定义一段程序模块为过程,并命名过程名。,7.3 模块化程序设计,说明: ProcedureFunction命令表示一个过程的开始,并命名过程名。过程名必须以字母或下划线开头,可包含字母、数字和下划线。 EndProcEndFunc语句表示一个过程的结束。如果省略EndProcEndFunc语句,那么过程结束于下一条ProcedureFunction命令外或文件结尾。, 当过程执行到
23、Return命令时,控制将返回到调用程序(或命令窗口),并返回表达式的值。如果省略Return命令,则在过程结束处自动执行一条隐含的Return命令。若Return命令不带,则返回逻辑真.T.。 过程可以放置在程序文件代码的后面,也可以保存在称为过程文件的单独文件里,文件的默认扩展名还是.prg。, 过程文件里只包含过程,这些过程能被任何其他程序所调用。过程文件的建立与程序文件的建立、编辑完全相同,只是在程序的最后要加上返回语句return 返回调用处; MODIFY COMMAND 过程名(.prg) 但调用之前首先要打开过程文件。打开过程文件的命令格式为: Set Procedure To
24、 , AddItive 可以打开一个或多个过程文件。一旦打开了一个过程文件,那么该过程文件中的所有过程都可以被调用。如果选用AddItive,那么在打开过程文件时,不关闭原先已打开的过程文件。, 使用不带任何文件名的Set ProcEdure To命令将关闭所有打开的过程文件。如果不想关闭所有打开的过程文件,而只关闭指定的过程文件,可使用下述命令:Release ProcEdure ,,,2. 调用模块 格式1:Do 功能:使用Do命令调用模块程序(过程)。 格式2:( ) 功能:在名字后加一对小括号表示调用模块程序(过程)。 说明 在上面的两种格式里,如果模块是一个单独的程序文件,用;否则,
25、用。 格式2既可以作为命令使用(忽略返回值),也可以作为函数出现在表达式里。在这里,不能包含扩展名。,*主程序: Set Procedure To d:ssprgf2, d:ssprgf3 ?“主程序开始“ DO f2 Do p1 ?“主程序结束“ Cancel*过程p1 Procedure p1 ?“过程p1开始“ ?“调用p3()“ ?“返回值:“,p3() ?“过程p1结束“ EndProc,*子程序:f2.prg ?“子程序f2开始“ ?“调用p2()“ x=p2() ?“返回值为:“,x ?“子程序f2结束“ Return*过程文件:f3.rg Procedure p2 Return
26、 Procedure p3 Return 100,作用域:指变量在什么范围内有效或能够访问。即变量的作用范围,分公共变量、私有变量和局部变量。 1)公共变量:在任何模块中都可以使用的变量, 公共变量需要先建立后使用。 Public :建立公共变量,并赋初值 为假值.f.。 公共变量只有在执行clear memory 、release、 quit等命令后才被释放,变为无效变量。 命令窗口中建立的所有内存变量都为公共变量。,7.3.2 模块程序中变量的作用域,2)私有变量:在程序中直接使用而无须声明的变量,其作用域为建立它的本模块和它的下属模块,当建立它的模块运行结束,则私有变量将自动释放。 3)
27、局部变量 只在建立它的模块中使用,不能在上层或下层中使用。 Local 局部变量必须先建立后使用。当建立它的模块程序运行结束时,局部变量自动释放。,Public x1 &建立公共变量x1,初值为.F. Local x2 &建立局部变量x2,初值为.F. Store “ok“ To x3 &建立私有变量x3,初值为.F. Do p6 ?“主程序中“ &三个变量在主程序中都可以使用 ?“xl=“,x1 ?“x2=“,x2 ?“x3=“,x3 Return *过程p6 Procedure p6 ?“子程序中“ &公共变量和私有变量在子程序中可以使用 ?“xl=“,x1 *?“x2=“,x2 &局部变
28、量x2在子程序中不可以使用 ?“x3=“,x3 Return,*clea all &注意此语句的作用,直接影响公共变量的值 Public x1 &建立公共变量x1,初值为.F. Local x2 &建立局部变量x2,初值为.F. Store “ok“ To x3 &建立私有变量x3,初值为.F. ?“主程序调用p6前“ ?“xl=“,x1 ?“x2=“,x2 ?“x3=“,x3 Do p6 ?“主程序调用p6后“ &三个变量在主程序中都可以使用 ?“xl=“,x1 ?“x2=“,x2 ?“x3=“,x3 Return *过程p6 Procedure p6 ?“子程序中“ x1=10 &公共变量
29、和私有变量在子程序中可以使用 ?“xl=“,x1 x2=20 ?“x2=“,x2 x3=30 &局部变量x2在子程序中不可以使用 ?“x3=“,x3 Return,4)隐藏变量 目的:隐藏在上层模块中已经建立的私有变量, 使得这些变量在当前模块中暂时无效,这样就 可以在当前模块中定义与上层模块同名的变量, 该变量的使用不影响上层同名的变量的值。 格式:private 或private all like |except Local命令也可以隐藏本模块中与上层同名的变量,Clear a1=10 a2=15 ?“a1=“+STR(a1),“a2=“+STR(a2) & 显示a1=10 a2=15 D
30、o p7 ?“a1=“+STR(a1),“a2=“+STR(a2) & 显示a1=10 a2=100*过程 p7 Procedure p7 Private a1 a1=50 a2=100 ?“a1=“+STR(a1),“a2=“+STR(a2) & 显示a1=50 a2=100 Return,【例】Local和Private命令程序示例。 Clear Public x,y x=10 y=100 Do p8 ?x,y &显示10 bbb *过程p8 Procedure p8 Private x &隐藏上层模块中的变量x x=50 &建立私有变量x,并赋值50 Local y &隐藏同名变量,建立
31、局部变量y Do p9 ?x,y &显示aaa .F.*过程p9 Procedure p9 x=“aaa“ & x是在p8中建立的私有变量 y=“bbb“ & y是在主程序中建立的公共变量 Return,(1) 接收参数的命令格式 格式1:Parameters ,, 格式2:LParameters ,, 功能:接收模块以形参变量接收调用模块程序传递过来的参数(称为实参)值。 说明: Parameters命令中声明的形参变量是模块程序中建立的私有变量,LParameters命令中声明的形参变量是模块程序中建立的局部变量。除此之外,两条命令没有什么不同。 不管是Parameters命令还是LPar
32、ameters命令,都应该是模块程序的第一条可执行命令。,7.3.3 调用模块时传递参数,(2) 调用模块程序时传递参数的命令格式 【格式1】Do With , 【格式2】 (,) 【功能】调用模块以实参向接收模块程序的形参变量传递值。 【说明】 实参可以是常量、变量,也可以是一般形式的表达式。调用模块程序时,系统会自动把实参传递给对应的形参。形参的数目不能少于实参的数目,否则系统会产生运行时错误。如果形参的数目多于实参的数目,那么多余的形参取逻辑假.F.初值。, 采用格式1调用模块程序时,如果实参是常量或一般形式的表达式,系统会计算出实参的值,并把它们赋给相应的形参变量。这种情形称为按值传递
33、。如果实参是变量,那么传递的是变量的地址,这时形参和实参实际上是同一个变量(尽管它们的名字可能不同),在模块程序中改变形参变量值也将改变实参变量值。这种情形称为按引用传递。, 采用格式2调用模块程序时,默认情况下都以按值传递方式传递参数。如果实参是变量,可以通过Set Udfparms命令重新设置参数传递的方式。该命令如下。 【格式】Set Udfparms To ValueReference 【说明】 使用To Value表示按值传递,改变形参变量的值不会影响实参变量的取值。 使用To Reference表示按引用传递,改变形参变量值时,实参变量值也随之改变。,【例】引用传递和按值传递程序示
34、例。,Clear Store 100 To x1,x2 Set Udfparms To Value &设置按值传递 Do p4 With x1,(x2) & x1按引用传递,x2按值传递 ?“第一次:“,x1,x2 Store 100 To x1,x2 p4(x1,x2) & x1、x2都按值传递 ?“第二次:“,x1,x2 Set Udfparms To Reference &设置按引用传递 Do p4 With x1,(x2) & xl按引用传递,x2按值传递 ?“第三次:“,x1,x2 STore 100 To x1,x2 p4(x1,x2) ?“第四次:“,x1,x2,*过程p4 Pr
35、ocedure p4 Parameters x1,x2 Store x1+1 To x1 STore x2+2 To x2 ENDProc 程序运行后显示结果为: 第一次: 101 100 第二次: 100 100 第三次: 101 100 第四次: 101 102,数组作参数,在调用程序和被调用程序之间传递的参数还可以是数组。当实参是数组元素时,总是采用按值传递方式传递元素值。当实参是数组名时,若传递方式是按值传递,那么就传递数组的第一个元素值给形参变量;若传递方式是按引用传递,那么传递的将是整个数组。,数组作参数,Clear Dime s(10) For i=1 To 10 S(i)=i
36、EndFor Do p5 With s ?s(1),s(2),s(3),s(4),s(5) ?s(6),s(7),s(8),s(9),s(10),程序运行后显示结果为: 10 9 8 7 6 5 4 3 2 1,Procedure p5 Parameters x For i = 1 To 5 t = x(I) x(I) = x(11-I) x(11-I) = t EndFor Return,clea dime a(10) for i=1 to 10input to a(i)next for i=1 to 10?a(i) endfor? do sort with a for i=1 to 10?
37、a(i) endfor,proc sortparame sfor i=1 to 9for j=1 to 10-iif s(j+1)s(j) t=s(j+1)s(j+1)=s(j)s(j)=tendiendf endf,输入10个数到数组中,然后按由小到大的顺序排序。,7.5 应用程序举例,【例7.18】编制程序,输出3100之间的所有素数。要判断一个数m是否为素数,可以用2到m-1的各个奇数去除m,如果都除不尽,m就是素数;只要有一个能除尽,m就不是素数。实际上为了提高效率,不必除到m-1,只要除到Int(SQRT(m)即可。 Clear a=1 For m=3 To 100 Step 2n=
38、Int(SQRT(m)For i=3 To nIf Mod(m,i)=0EXITEndIfEndFor,If in?ma=a+1IF a6?a=1EndIf EndIf EndFor Cancel,clear for x= 3 to 100 k=0 pd(x) if k=0 ?x,“is sushu“ else ?x,no endif endfor,proc pd para m for i=2 to sqrt(m)if mod(m,i)=0k=1exitendif next retu k end proc,【例7.19】编制一个查询学生情况的程序。要求根据给定的学号找出并显示学生的姓名及该学生
39、各门功课的成绩。,Open Database d:ssstudent Use stud In 0 Use sc In 0 SELECT sc Index On 学号 Tag xh SELECT stud Index On 学号 Tag xh Set Relation To 学号 Into sc &建立一对多关联 Set Skip To sc Do While .T.ClearAccept “请输入学号“ To mxhSeek mxhIf !Eof() &找到学生记录mes=“学号:“+学号+“ 姓名:“+姓名,Do While sc.学号=mxh & Chr(10)和Chr(13)分别是换行符
40、和回车符 + “课程号:“ + sc.课程号 + “成绩:“ + STR(sc.成绩,5,1)SkipEndDomes=mes+Chr(10)+Chr(13)+“按任意键继续“ Else &未找到学生记录mes=“查无此人,按任意键继续“ EndIf Wait mes Window Wait “继续查询吗?(YN)“ To p If Upper(p) “Y“Exit EndIf EndDo Close Database Cancel,利用Select-SQL语句实现自动查询的代码,Open Database d:ssstudent Do While .T.ClearAccept “请输入学号“ To mxhSelect stud.学号, stud.姓名, sc.课程号, sc.成绩;From stud, sc;Where stud.学号 = sc.学号 .And. stud.学号 = mxh NoWaitWait “继续查询?(YN)“ To pIf Upper(p) “Y“Use &关闭查询窗口ExitEndIf EndDo Close Database Cancel,