520 likes | 723 Views
第 7 章 程序设计基础. 本章要点. 程序与程序文件,程序概念、程序文件的建立与运行、简单的输入输出命令 程序的基本结构,顺序结构、选择结构 、循环结构 多模块程序,模块的定义和调用、变量的作用域 程序调试,调试器环境、设置断点、调试菜单. 7.1 程序与程序文件. 7.1.1 程序的概念. 1 .程序 定义: 程序是能够完成一定任务的命令的有序集合。这组命令被存放在称为程序文件或命令文件的文本文件中。 2 .程序方式 优点: 程序可以被修改并重新运行。 可以用多种方式、多次运行程序。 在一个程序中可以调用另一个程序。
E N D
本章要点 • 程序与程序文件,程序概念、程序文件的建立与运行、简单的输入输出命令 • 程序的基本结构,顺序结构、选择结构 、循环结构 • 多模块程序,模块的定义和调用、变量的作用域 • 程序调试,调试器环境、设置断点、调试菜单
7.1.1 程序的概念 • 1.程序 • 定义: • 程序是能够完成一定任务的命令的有序集合。这组命令被存放在称为程序文件或命令文件的文本文件中。 • 2.程序方式 • 优点: • 程序可以被修改并重新运行。 • 可以用多种方式、多次运行程序。 • 在一个程序中可以调用另一个程序。 • 具有在命令窗口中无法使用的结构化程序设计命令。
例如:编写程序,计算圆的周长和面积。 • 程序过程 • CLEAR • && 清除Visual FoxPro主窗口上的全部内容 • *设置半径 • R=3* • 依次计算圆的周长和面积 • L=2*PI()*R • S=PI()*R^2 • *输出计算结果 • ?”周长=”,L?”面积=”,S
说明: • 程序中经常插入注释,以提高程序的可读性。注释为非执行代码,不会影响程序的功能。 • 注释方式: • NOTE<注释内容>或*<注释内容> • 以NOTE或*开头的代码行为注释行,一般用于对下面一段命令的说明。 • &&<注释内容> • 命令行后可添加注释,对所在行命令的说明。
7.1.2 程序文件的建立与运行 • 1.程序文件的建立 • 方法: • 选择“文件”菜单中的“新建”命令,然后在“新建”对话框中选择“程序”,并单击“新建文件”按钮。 • 在文本编辑窗口中输入程序内容。 • 保存程序文件。 • 2.打开、修改程序文件 • 方法:
方法: • 选择“文件”菜单中的“打开”命令,弹出“打开”对话框。 • 在“文件类型”列表框中选择“程序”。 • 在文件列表框中选定要修改的文件,单击“确定”按钮。 • 修改后,选择“文件”菜单中的“保存”命令或按Ctrl+W组合键保存文件。 • 可用MODIFY COMMAND〈文件名〉建立和修改程序文件。
3.执行程序文件 • 菜单方式: • 选择“程序”菜单中的“运行”命令,打开“运行”对话框;从文件列表框中选择要运行的程序文件,单击“运行”命令按钮。 • 命令方式: • DO〈文件名〉 • 当用DO命令执行程序文件时,如果没有指定扩展名,系统将按下列顺序寻找该程序文件的源代码或目标代码文件执行:.exe(Visual FoxPro可执行文件)→ .app(Visual FoxPro应用程序文件) →.fxp(Visual FoxPro编译文件)→.prg(Visual FoxPro源程序文件)。
7.1.3 简单的输入输出命令 • 1.INPUT命令 • 命令格式: • INPUT <字符表达式> TO <内存变量> • 命令说明: • 当程序执行到该命令时,程序暂停,等待用户从键盘输入数据,用户可以输入任意合法的表达式。 • 当用户以Enter键结束输入时,系统计算表达式的值并将表达式的值存入指定的内存变量,程序继续向下运行。
2.ACCEPT命令 • 命令格式: • ACCEPT <字符表达式> TO <内存变量> • 命令说明: • 当程序执行到该命令时,程序暂停,等待用户从键盘输入字符串。 • 当用户以回车键结束输入时,系统将该字符串存入指定的内存变量,程序继续向下运行。
3.WAIT命令 • 命令格式: • WAIT [cMessageText] [TO VarName] [WINDOW [AT nRow,nColumn]][NOWAIT] [CLEAR | NOCLEAR] [TIMEOUT nSeconds] • 命令说明: • 显示该字符表达式的值作为提示信息,程序暂停,直到用户按任意键或单击鼠标时,程序继续执行。
7.2.1 顺序结构 • 1.顺序结构 • 定义: • 顺序结构程序设计就是根据事物的处理顺序和要求,将相应的指令按照它们所完成的功能有机地结合起来的一个指令序列,这些指令的执行是按它们的排列顺序一条接一条的来执行。
2.选择结构 • 条件语句 • 命令格式: • IF lExpression • Commands1 • [ELSE • Commands2] • ENDIF • 命令说明: • IF和ENDIF必须成对出现,IF是本结构的入口,ENDIF是本结构的出口。 • 条件语句可以嵌套,但不能出现交叉。在嵌套时,为了使程序清晰、易于阅读,可按缩进格式书写。
分支语句 • 命令格式: • DO CASE • CASE lExpression1 • Commands1 • [CASE lExpression2 • Commands2 • … • CASE lExpressionN • CommandsN • [OTHERWISE • Commands] • ENDCASE
7.2.2 循环结构 • 1.循环结构 • 定义: • 循环结构也成为重复结构,是指程序在执行的过程中,其中的某段代码被重复执行若干次。被重复执行的代码段,通常称为循环体。 • 分类: • FOR-ENDROR • DO WHILE-ENDDO • SCAN-ENDSCAN
2.FOR语句 • 定义: • 该语句常用于实现循环次数已知情况下的循环结构。 • 命令格式: • FOR MemVarName=nInitialValue TO nFinalValue [SETP nIncrement] • Commads • [EXIT] • [LOOP] • ENDFOR|NEXT
命令说明: • SETP nIncrement的默认值为1。 • 可以在循环体内改变循环变量的值,但是这会影响循环体的执行次数。 • EXIT在循环结束时,将控制从循环体内转移到ENDFOR后面的命令。 • LOOP给定该参数,可以控制程序直接返回到FOR,而不去执行LOOP后面的指令序列,但不影响计数器的正常工作。
3.DO WHILE-ENDDO语句 • 命令格式: • DO WHILE lExpression • Commands • [LOOP] • [EXIT] • ENDDO • 命令说明: • 条件lExpression是个逻辑表达式,如果第一次判断条件时,lExpression为假,则循环体一次也不执行。
执行DO WHILE语句时,系统先对表达式求值,如果为真,则顺序执行循环体内的各条语句。 • 如果循环体包含LOOP命令,那么当遇到LOOP时,就结束循环体的本次执行,不执行其后面的语句,而是回到DO WHILE外重新判断条件。 • 如果循环体包含EXIT命令,那么当遇到EXIT时,就结束该语句的执行,转去执行ENDDO后面的语句。 • 通常LOOP或EXIT出现在循环体内嵌套的选择语句中,根据条件决定是LOOP回去,还是EXIT出去。 • DO WHILE与ENDDO必须成对出现。
4.SCAN-ENDSCAN语句 • 命令格式: • SCAN [NOOPTIMIZE] • [Scope][FOR lExpression1][WHILE lExpression2] • [Commands] • [LOOP] • [EXIT] • ENDSCAN • 命令说明: • 〈范围Scope〉的默认值是ALL。
该语句自动切换记录指针到下一条符合条件的记录,其功能相当于LOCATE、CONTINUE和DO WHILE-ENDDO语句功能的合并。 • EXIT和LOOP命令同样可以出现在该循环语句的循环体内。 • 循环结构是可以嵌套使用的,但是要注意嵌套的结构的次序。下一个循环体一定要在上一个循环体内,它们之间不允许交叉嵌套。
5.循环结构的嵌套使用 • 错误的命令格式: • DO WHILE1 • FOR1 • …… • ENDFOR1 • ENDDO1 • 正确的使用嵌套结构可使程序更清晰,可读性更强。
6.程序举例 • 例如:编写程序,计算:T=1!+2!+……+100! • 求100!的程序代码如下: • y=1 • FOR n=1 to 100 • y=y*n • ENDFOR • 说明: • 先为变量y赋初值1,然后通过循环语句将命令y=y*n重复执行100次,循环体每次执行时,n的值依次取1、2、……、100,循环体每次执行后,Y的值依次为1!、……、100!。
方法1: • 在上述程序代码中添加一条命令x=x+y,也就是把代码执行过程中产生的各Y值累加起来,那么最终的X值就是所要求的各阶乘之和。 • x=0 • y=1 • FOR n=1 to 100 • y=y*n • x=x+y • endfor • ?'x=',x
方法2: • 在求100!时,将FOR子句改成for i=1 to n,代码段的功能就变成了n!。将求n!的代码段重复执行100次,n的值从1变到100。最后将每次执行产生的阶乘累加起来。 • x=0 • for n=1 to 100 • y=1 • for i=1 to n • y=y*i • endfor • x=x+y • endfor • ?'x=',x • return
例如:找出100——900之间的所有“水仙花数”。例如:找出100——900之间的所有“水仙花数”。 • 所谓“水仙花数”是指一个三位数,其各位数字的立方和等于该数本身。(如153=13+53+33) • 这题的关键是要知道如何分离出一个三位数中的各位数字。下面列出两种方法,其中i代表三位数,a、b和c分别代表该三位数的百位、十位和个位上的数字。
方法1: • CLEAR • FOR i=100 TO 900 • a=INT(i/100) • && INT(153/100)等于1 • b=INT((i-100*a)/10) • && INT((153-100*a)/10)等于5 • c=i-INT(i/10)*10 • && 153-INT (153/10) *10 • IF i=a^3+b^3+c^3 • ?i • ENDIF • ENDFOR • RETURN
方法2: • Clear • FOR i=100 TO 900 • s=STR(i,3) • && 将一个三位数转换成字符串 • a=VAL(LEFT(s,1)) • && 将字符串最左边的一个数字字符转换为数值 • b=VAL(subs(s,2,1)) • && 将字符串最中间的一个数字字符转换为数值 • c=VAL(right(s,1)) • && 将字符串最右边的一个数字字符转换为数值
IF i=a^3+b^3+c^3 • ?i • ENDIF • ENDFOR • RETURN
7.3.1模块的定义和调用 • 1.模块的定义 • 定义: • 模块可以是命令文件,也可以是过程。 • 过程定义的语法格式: • PROCEDURE | FUNCTION<过程名> • <命令序列> • [RETURN[<表达式>]] • [ENDPROC︱<ENDFUNC>]
打开过程文件的命令格式: • SET PROCEDURE TO[<过程文件1>[<过程文件2>,…]] [<ADDITIVE>] • 关闭过程文件的命令格式: • RELEASE PROCEDURE TO[<过程文件1>[,<过程文件2>,…] • 2.模块调用 • 格式1: • DO <文件名>︱<过程名> • 格式2: • <文件名>︱<过程名>()
说明: • 如果模块是程序文件的代码,模块调用就用<文件名>。 • 如果模块不是程序文件的代码,模块调用就用<过程名>。 • 格式2的模块调用既可以作命令使用,也可以当作函数出现在表达式中。 • 格式2中的<文件名>不能含有扩展名。
7.3.2 参数传递 • 1.PARAMETERS和LPARMETERS语句传递参数 • 格式: • PARMETERS<形参变量1>[,<形参变量2>,…] • LPARMETERS [<形参变量1>1>[,<形参变量2>,…] • 2.调用模块程序 • 格式1: • DO <文件名>︱<过程名>WITH<实参1>[,<实参2>,…]
格式2: • DO <文件名>︱<过程名><实参1>([,<实参量2>,…]) • 3.参数传递方式 • 按“引用”传递 • TO REFERENCE:按引用传递。 • 采用1调用模块程序时,如果实参是常量或一般形式的表达式,系统会计算出实参的值,并把它们赋给相应的形参变量,称为按值传递。如果实参是变量,则传递的将不是变量的值,而是变量的地址。 • 按“值”传递 • TO VALUE:按值传递。
采用2调用模块程序时,默认情况下是以按“值”方式传递参数。如果实参是变量,可以利用SET UDFPARMS命令重新设置参数传递的方式。 • 还可以在程序之间传递数组。 • 当实参是数组元素时,总是采用按值方式传递元素值。 • 当实参是数组名是,如果按“值”方式传递数组元素值时,则传递数组的第一个元素值给形参变量。 • 如果按“引用”方式传递数组元素值时,则传递的将是整个数组。
例如:按值传递和按引用传递。 • CLEAR • STORE 500 TO X1,X2 • SET UDFPARMS TO VALUE • DO P4 WITH X1,(X2) • ?'第一次:',x1,x2 • STORE 500 TO x1,x2 • P4(X1,(X2)) • ?'第二次:',x1,x2 • SET UDFPARMS TO REFERENCE • DO P4 WITH X1,(X2) • ?'第三次:',x1,x2
STORE 500 TO x1,x2 • P4(X1,(X2)) • ?'第四次:',x1,x2 • *过程P4 • PROCEDURE P4 • PARAMETERS X1,X2 • STORE X1+1 TO X1 • STORE X2+1 TO X2 • ENDPROC
7.3.3 变量的作用域 • 1.变量的作用域 • 定义: • 指变量在什么范围内是有效的或者能够被访问的。 • 内存变量分类: • 公共变量 • 公共变量又称为全局变量,在任何程序或过程中都可以使用的内存变量。 • 如果某数据需要在程序中任何地方取用,为方便起见,就可定义为公共变量。 • 定义公共变量用PUBLIC命令。
私有变量 • 在程序中直接使用(没有通过PUBLIC和LOCAL命令事先声明)并且由系统自动隐含建立的变量称为私有变量。 • 私有变量通常用于过程中,其作用范围仅限于此过程中与在此过程中的过程,外部的程序无法作用到此类变量,而此类变量在进入此过程时才被定义,离开此过程后即被释放。 • 定义私有变量用PRIVATE命令。一旦建立它的模块程序运行结束,这些私有变量将自动清除。
局部变量 • 未经PUBLIC定义的内存变量均为局部变量。局部变量只能在建立它的模块中使用,不能在上层或下层模块中使用。 • 当建立它的模块程序运行结束时,局部变量自动释放。 • 与全局变量一样,局部变量也要先建立后使用。 • 局部变量用LOCAL命令定义。
2.变量的隐藏 • 开发应用程序时,主程序与子程序不一定是由同一个人来设计的,子程序中用到的变量实际上在主程序中已经建立,子程序的运行会无意间改变主程序中变量的取值。 • 为了解决这个问题,可以采用在子程序中使用PRIVATE命令隐藏主程序中可能存在的变量,使得这些变量在子程序中暂时无效。 • 例如:变量的隐藏。 • SET TALK OFF • V1=100
SET TALK OFF • V2=150 • DO P • ?V1,V2 && 显示100 1000 • *过程P • PROCEDURE P • PRIVATE V1 • V1=500 • V2=1000 • ?V1,V2 && 显示500 1000 • RETURN
7.4.1 调试器环境 • 1.调用调试器 • 方法: • 选择“工具”菜单中的“调试器”命令 • 在命令窗口中输入DEBUG命令 • 2.“调试器”的5个子窗口 • “跟踪”窗口 • “监视”窗口 • “局部”窗口 • “调用堆栈”窗口 • “调试输出”窗口
7.4.2 设置断点 • 1.在代码行上设置断点 • 方法: • 把光标定位在某一行上,然后按Space键,或者双击灰色区域。 • 在调试器菜单上选择“工具”下的“断点”,或单击工具栏上的按钮,屏幕将显示一个“断点”对话框。 • 断点的类型: • 在定位处中断 • 如果表达式值为真则在定位处中断 • 当表达式值为真时中断 • 当表达式值改变时中断
7.4.3 调试菜单 • 1.“调试”菜单主要包括 • 运行 • 继续执行 • 取消 • 定位修改 • 跳出 • 单步 • 单步跟踪 • 运行到光标处 • 调速 • 设置下一条语句
例如:调试下面的程序找出100——900之间的所有“水仙花数”。例如:调试下面的程序找出100——900之间的所有“水仙花数”。 • 操作步骤如下: • 打开程序在命令CLEAR之后添加“DEBUGOUT‘下面是100至900之间的所有水仙花数’”,在命令?I前添加DEBUGOUT I。 • 在跟踪窗口中打开程序后,在命令?I处设置类型1断点;在表达式I=A^3+B^3+C^3上设置类型4断点。 • 选择“工具”菜单中的“调试器”命令打开调试器窗口。