第 7 章 程序设计

50
第7第 第第第第 第 第 第 第 第 第 第第第第第第第第第第 第第第第第第第 第第第第第 第第第第 第第第第 第第第第 第第第第 第第第第 第第第第 第第第第

Upload: jordan-bowman

Post on 30-Dec-2015

78 views

Category:

Documents


5 download

DESCRIPTION

第 7 章 程序设计. 本 章 主 要 内 容 程序文件的建立与运行 程序的控制结构 多模块程序 数组应用 教 学 方 法 教师讲解 学生自学 独立思考 上机多练 合作学习 提高能力. 第 7 章 程序设计. 程序设计的步骤 进行程序设计一般要经过以下步骤,如图 7-1 所示。 a .分析问题或任务,总结或抽象出问题的数学模型。 b .根据数学模型确定解决问题的算法思想。 c .根据算法思想确定要建立的数据表或数据库的基本结构及其数据表之间的关系。 d .画出程序流程图。 e .编写程序,实现功能要求,并在计算机上调试通过。 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 第 7 章   程序设计

第 7 章 程序设计本 章 主 要 内 容

程序文件的建立与运行 程序的控制结构 多模块程序 数组应用

教 学 方 法 教师讲解 学生自学 独立思考 上机多练 合作学习 提高能力

Page 2: 第 7 章   程序设计

第 7 章 程序设计程序设计的步骤

进行程序设计一般要经过以下步骤,如图 7-1 所示。

a .分析问题或任务,总结或抽象出问题的数学模型。

b .根据数学模型确定解决问题的算法思想。c .根据算法思想确定要建立的数据表或数据库

的基本结构及其数据表之间的关系。d .画出程序流程图。e .编写程序,实现功能要求,并在计算机上调

试通过。f .用典型数据对所编写的程序进行测试,验证

程序的可靠性。发现问题进行修改,修改后再进行调试,直到程序正确运行为止。

g .编写使用说明书,整理有关资料,进行总结。 图 7-1 程序设计步骤

Page 3: 第 7 章   程序设计

第 7 章 程序设计7.1 程序文件的建立与运行

7.1.1 程序文件的建立 程序文件的建立有菜单和命令两种方式,菜单方式请大家参考书上操作步骤进行学习,这里我们讲解命令操作方式。1. 命令方式建立程序文件格式: MODIFY COMMAND [< 程序文件名 >]|?功能:打开程序编辑窗口,从中可以修改或创建程序文件。 a. < 程序文件名 > :指定修改或创建的程序文件名。若省略程序文件名, MODIFY COMMAND 命令将打开图 7-3 所示的程序编辑窗口。b. 如果不指定程序文件名, MODIFY COMMAND 后面跟 ? 号,则显示“打开”对话框,如图 7-4 所示,在“文件类型 (T)” 右边下拉列表中选定文件类型为【程序 (*.prg;*.spr;*.mpr;*.qpr) 】;在“查找范围 (I)” 右边下拉列表中选定相关程序文件所在的文件夹;从选定文件夹中,选择一个已有程序文件或在“文件名 (N)”右边文本框中键入要创建的新程序文件名,单击【确定】按钮,即可在程序编辑窗口打开指定文件名的程序文件。C. 命令程序文件的扩展名是 .PRG 。

图 7-3 程序编辑窗口

图 7-4 “ 打开”对话框

Page 4: 第 7 章   程序设计

第 7 章 程序设计7.1 程序文件的建立与运行

7.1.1 程序文件的建立2. 在程序编辑窗口中输入命令[ 例 7-1] 编写两个变量的加法运算程序。编写步骤如下:步骤 1 :在命令窗口里输入: MODIFY COMMAND CX1 &&CX1 是程序文件名,扩展名 .PRG 在这里可以省略。步骤 2 :在程序编辑窗口(图 7-3)输入如下 6条命令。 CLEAR &&将屏幕输出窗口内容清空 a=12 &&将数值 12赋值给变量 a b=18 &&将数值 18赋值给变量 b c=a+b &&将变量 a 与 b 的和计算出来,赋值给变量 c ?a,b,c &&输出变量 a、 b、 c 的值 RETURN &&表示程序结束。 在输入一个程序时,请用户注意以下几点: a. 一个命令语句中只能有一个命令动词; b. 每输入完一个语句按“回车”键表示该语句结束; c. 程序中用到的所有作为“分隔符号”的标点符号一律用半角符号; d. 每一个程序最后一般应有一个结束语句,以表示该程序的结束。

Page 5: 第 7 章   程序设计

第 7 章 程序设计7.1 程序文件的建立与运行

7.1.1 程序文件的建立3. 程序文件的保存、打开与关闭( 1)程序文件的保存 按快捷键 Ctrl+W将文件进行保存。 本章的程序文件名按如下规则命名, [ 例 7-1] 用 cx1、 [ 例 7-2] 用 cx

2 , ...... ,依此类推。( 2)程序文件的打开 在命令窗口里,利用“ MODIFY COMMAND < 程序文件名 >” 命令打

开指定程序文件,进行编辑修改。( 3)程序文件的关闭 a. 单击菜单【文件 (F) 】→【关闭 (C) 】命令; b. 单击程序编辑窗口右上角的【×】关闭按钮; c. 在“命令”窗口里输入命令: CLOSE ALL ; d. 按快捷键 Ctrl+W,保存并关闭程序文件。

Page 6: 第 7 章   程序设计

第 7 章 程序设计7.1 程序文件的建立与运行

7.1.2 程序的运行

用命令方式运行程序 格式: DO < 程序文件名 > 功能:将指定的程序文件调入内存并运行。 说明: a. 默认程序扩展名为 .PRG ,可不必输入; b. 该命令可在命令窗口里输入执行,也可以出现在另一个程序文件中,后者可实现在一个程序中调用另一个程序。 如在命令窗口里输入: DO cx1 执行程序 cx1 后,将在屏幕输出程序计算结果: 12 18 30 在程序打开并且为当前程序的情况下,单击常用工具栏上【 !】命令按钮也可以执行程序。

Page 7: 第 7 章   程序设计

第 7 章 程序设计7.1 程序文件的建立与运行

7.1.3 程序中的辅助命令 Visual FoxPro还提供了一些辅助命令,如注释命令、程序结束命令、运行环境设置命令等,这些命令能使程序更好地阅读和有效地运行 1. 程序注释命令 VFP 提供了 3 种程序设计注释命令:格式 1 : NOTE <注释内容 >格式 2 : * <注释内容 >功能:使 NOTE或 * 后面的内容成为注释内容。格式 3 : [< 命令 >] &&<注释内容 >功能: <注释内容 > 对 &&左面的命令做出解释或给出运行结果,又称为行尾注释命令。 这些命令如何在程序中的使用将在以后的程序设计中给出。

Page 8: 第 7 章   程序设计

第 7 章 程序设计7.1 程序文件的建立与运行

7.1.3 程序中的辅助命令2. 程序结束命令 格式 1 : RETURN 功能:返回到上一级模块。如果本程序是以菜单方式或在命令窗口中调用执行的,则返回到命令交互状态即命令窗口。 格式 2 : CANCEL 功能:结束程序运行,关闭程序中所有的文件和变量,返回到交互状态即命令窗口。 格式 3 : QUIT 功能:关闭Visual FoxPro,返回到操作系统 对一个独立程序来说,一般在最后一条语句要用 RETURN 命令,以表示程序的结束。 3. 运行环境设置命令 在程序中运用一些环境设置命令,可使程序正常而高效地运行。常用的环境设置命令如教材表 7-1 所示。

Page 9: 第 7 章   程序设计

第 7 章 程序设计7.1 程序文件的建立与运行

7.1.4 交互式的输入命令 根据解决实际问题的需要,往往在程序运行的过程中,由用户向程序输入一些数据或信息,完成这种功能的一些命令称为交互式输入命令。 Visual FoxPro提供了多种交互式输入命令。

说明: a. [< 提示信息 >] ,是在屏幕上出现的提示信息。它可以是字符串,此时必须用双引号将其括起来,也可以是字符型内存变量,此时该内存变量必须预先赋值。b. 用户在键盘输入的任何字符信息都被赋值给“内存变量”。输入的数据将作为字符型数据处理,不需要定界符括起来,如果输入了定界符,则这些定界符也被作为输入字符的一部分,一起存入到内存变量中。c. 输入完需要的信息后,按 Enter 键结束本命令的输入。如果没有输入其他信息,只输入一个回车键,将把一个空字符赋值给内存变量。

[ 例 7-2] 编一程序,将人事数据表打开,在程序运行中输入人员姓名,显示指定姓名的人员记录。该程序编写步骤为:步骤 1 :在命令窗口里输入命令: MODIFY COMMAND CX2步骤 2 :在打开的程序窗口里输入如下语句:NOTE 该程序查找指定姓名的人员信息。CLEARUSE rsbACCEPT "请输入要查找的姓名: " TO nameLOCATE FOR ALLTRIM(姓名 )=nameDISPLAYRETURN 步骤 3 :按 Ctrl+W保存该程序步骤 4 :运行程序,在命令窗口里输入: DO CX2

1. 字符型数据输入命令 ACCEPT格式: ACCEPT [< 提示信息 >] TO < 内存变量 >功能:暂停程序的执行,等待用户输入一个字符串给变量

Page 10: 第 7 章   程序设计

第 7 章 程序设计7.1 程序文件的建立与运行

7.1.4 交互式的输入命令

说明:a. [< 提示信息 >] ,同“ ACCEPT” 命令中的 [<

提示信息 >]含义。b. 用户可输入任何一个合法的数值型( N)、字符型( C)、日期型( D)、逻辑型( L)表达式,系统先计算表达式的值并将该值赋值给内存变量。

c. 如果输入字符串信息,则必须加上双引号或单引号定界符,如 "ABC"。

d. 按 Enter 键结束输入,系统将表达式的值赋值给内存变量。

e. 如果输入的是非法表达式,系统将提示您重新输入。

[ 例 7-3] 已知圆半径为 r ,求圆面积 s(要求四舍五入保留三位小数)。假设圆的半径为 r ,则计算圆面积 s 的公式为: s=πr2 ,计算圆面积公式的 Visual FoxPro表达式为: PI()*r^2 。程序编写步骤如下:步骤 1 :在命令窗口里输入: MODIFY COMMAND CX3步骤 2 :在打开的程序窗口里输入如下语句:* 该程序用于计算指定半径的圆的面积。CLEARINPUT "请输入圆半径 r=" TO rs=ROUND(PI()*r^2,3) &&ROUND函数为四舍五入函数

?" 该圆半径为: ",r?" 该圆面积为: ",sRETURN 步骤 3 :按 Ctrl+W保存该程序文件。步骤 4 :在命令窗口里输入运行命令: DO CX3

2. 表达式输入命令 INPUT格式: INPUT[< 提示信息 >]TO < 内存变量 >功能:暂停程序的执行,接受用户输入合法表达式并将表达式的值赋值给内存变量。

注意:请认真掌握程序编写与运行的 4 个步骤,以后例题中只说明“步骤 3” 。

Page 11: 第 7 章   程序设计

第 7 章 程序设计7.1 程序文件的建立与运行

7.1.4 交互式的输入命令

说明: a. [< 提示信息 >] ,指定要显示的自定义信息。若省略该参数,则 Visual FoxPro 显示默认的信息“按任意键继续……”。如果该参数为空字符,则不显示信息。

b. [WINDOWS] :在 Visual FoxPro 主窗口右上角的系统信息窗口中,显示提示信息。如果指定 [AT < 行坐标 >,< 列坐标 >] ,则该窗口在指定屏幕坐标位置显示。

c. TIMEOUT <等待秒数 > :指定在执行 WAIT 命令之后,程序暂停的时间, <等待秒数 > 参数指定等待的时间秒数。

d. NOWAIT子句指在前述指定的Windwos 窗口中显示WAIT信息的同时,程序继续执行而不暂停。

例如下列命令将在屏幕 18行、 18列位置处显示一含有提示信息的小窗口,如图 7-8所示。WAIT “ 请稍后,程序将继续执 ...... 。” ; WINDOWS AT 18,18 TIMEOUT 8

3. 程序暂停、等待接收单字符命令WAIT格式:WAIT [< 提示信息 >][TO < 内存变量 >][WINDOWS[AT < 行坐标 >,< 列坐标 >]] [TIMEOUT<等待秒数 >][NOWAIT]

功能:暂停程序,用户按任意键或者时间超过等待的秒数后,程序继续执行。如果包含 [TO < 内存变量>]短语,将用户所按键盘字符赋值给指定的内存变量。

图 7-8 WAIT 命令显示的信息窗口

此时单击鼠标按键、按下键盘上任意一个按键或小窗口在屏幕上停留 8秒后,从屏幕上消失。

Page 12: 第 7 章   程序设计

第 7 章 程序设计7.1 程序文件的建立与运行

7.1.4 交互式的输入命令

说明: a. @< 行 ,列 > 用于指定在屏幕上输出的行、列位置坐标。行和列均应是数值表达式,并且系统将自动对其进行取整数。

b. SAY < 表达式 > 子句用来在屏幕上指定的行、列位置输出指定表达式的值。

c. GET < 变量 > 子句用来在屏幕上输入指定变量的值,且必须与 READ 命令配套使用,带有 GET < 变量 >子句如果不与READ 命令配套使用,则指定的变量不能被输入数据。这里的变量应该预先赋初值或用 DEFAULT < 表达式 > 为其赋初值。

d. DEFAULT < 表达式 > 子句用来给 GET < 变量 > 子句中的变量赋初值。如果程序在该语句之前有对变量赋初值,就不要使用 DEFAULT < 表达式 >子句。

e. RANGE < 表达式 1>,< 表达式 2> 子句用来规定由 GET子句输入的数值型或日期型数据的上下界, < 表达式 1> 为下界, < 表达式 2> 为上界,这两个表达式的类型都必须与 GET子句中变量的类型一致。

f. VALID <条件 > 子句用来规定 GET子句输入的变量值所需符合的条件,以检测在 READ 操作时由键盘输入数据的合法性。

[ 例 7-4] 定位输出命令编程举例。将人事数据表打开,新增加一条记录部分字段内容,增加完成后在浏览窗口显示数据表记录内容,关闭浏览窗口,屏幕出现等待信息窗口,8 秒后,等待信息窗口关闭,清屏并关闭数据表,程序结束。该程序如下:CLEARUSE rsbAPPEND BLANK@ 3,8 SAY "请输入新职工信息: "@ 4,8 SAY "姓名: " GET 姓名 @ 5,8 SAY "性别: " GET 性别 VALID 性别$"男女 " @ 6,8 SAY "基本工资: " GET 基本工资 RANGE 500,2500READBROWSEWAIT "程序将在 8 秒后关闭 ...... 。 " WINDOWS AT 18,8 TIMEOUT 8USECLEARRETURN

4. 定位输出与输入命令格式:@< 行 ,列 > [SAY < 表达式 >] [GET < 变量 >] [DEFAULT < 表达式 >] [RANGE < 表达式 1>,< 表达式 2>] [VALID <条件 >]功能:在屏幕上指定行、列位置输出指定表达式的值,并且(或者)获得所指定变量的值。

Page 13: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构

程序设计包括三种基本结构,即顺序结构、选择结构、循环结构。7.2.1 顺序结构 顺序结构是程序设计中最基本的结构,该结构按照程序命令出现的先后顺序,依次执行。其它结构作为它的组成部分而存在于程序之中。事实上,程序中的命令如果不进行特殊说明,就自动按其前后排列顺序执行。我们以前介绍的几个例题都是顺序结构程序设计题目。再看例题7-5。

[ 例 7-5] 假设我国 2004年国民生产总值为 130,000 亿元,按每年平均8%的速度递增,编程计算到 2010 年我国国民生产总值将会达到多少?计算国民生产总值的公式为:未来值 p1= 初值 p0×( 1+ 速度 a)时间间隔

这里,初值 p0=130000 亿元,速度为 a=0.08,时间间隔 n=2010-2004=6, P1 为未来待计算的值。 Visual FoxPro计算表达式为: p1=p0*(1+a)^n 。该程序流程图如图 7-9所示。程序代码如下:CLEARp0=130000a=0.08n=6p1=p0*(1+a)^n?"我国 2004年的国民生产总值为: ",p0?"我国 2010 年的国民生产总值为: ",p1RETURN 图 7-9 例 7-5 程序框图

例题 7-6同学们自学,并总结一下,程序设计的方法。

Page 14: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构

7.2.2 选择结构 选择结构,是一种常用的基本结构,在一般程序中都要使用到它。按照选择结构执行路径的多少,可分为简单分支结构、双分支选择结构和多分支选择结构。无论是那种类型的选择结构,都是根据所给条件是否为真,选择执行某一分支的相应操作。

1. 简单分支结构 简单分支结构是由 IF语句开头,以 ENDIF语句结束的若干条命令组成的。 格式: IF <条件 > [ 命令序列 ] ENDIF说明: a. 根据 <条件 > 的逻辑值进行判断。如果 <条件 > 的逻辑值为 .T. ,就依次执行

[ 命令序列 ] ,执行完后就转去执行 ENDIF 之后的命令。如果 <条件 > 的逻辑值为 .F. ,则 IF<条件 > 和 ENDIF 之间的所有命令都不执行,而直接转到 ENDIF之后的命令。

b. IF语句和 ENDIF语句必须成对出现,且各占一行。 c. 为了程序阅读方便,便于以后维护修改,建议对于 [ 命令序列 ]部分采取向右缩进书写的方式。

Page 15: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构

7.2.2 选择结构1. 简单结构

[ 例 7-7] 铁路托运行李,按规定每张客票托运行李不超过 50公斤时,每公斤 0.25元,如超过 50公斤,超过部分按每公斤 0.45元计算。编写一个程序,把行李重量输入计算机,计算出运费,并打印出付款清单。问题分析:设行李重量为W公斤,应付运费为 P元,则运费公式为:p=0.25×w 当W≤50p=50×0.25+(w-50)×0.45 当W> 50根据以上分析,该问题计算机程序框图如图 7-13 所示。程序如下: NOTE 计算铁路托运行李费,W为行李重量, P 为运费。 CLEAR INPUT "请输入行李重量: " TO w P=0.25*w IF w>50 P=50*0.25+(w-50)*0.45 ENDIF ?"行李重量为: ",w ?"应付运费为: ",p RETURN 图 7-13 例 7-7 程序框图

例题 7-8同学们自学。

Page 16: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构

7.2.2 选择结构2.双分支简单结构

双分支选择结构也是由 IF语句开头,以 ENDIF语句结束的若干条命令组成的,但其中包含一条ELSE语句。格式: IF <条件 > [ 命令序列 1] ELSE [ 命令序列 2] ENDIF说明:a. 如果 <条件 > 的逻辑值为 .T. ,就执行 [ 命令序列 1] ,执行完后就转到执行 ENDIF 之后的命令。如果 <条件 > 的逻辑值为 .F. ,就执行 [ 命令序列 2] ,完成后,转去执行 ENDIF 之后的命令。b. ELSE语句单独占一行, IF语句和 ENDIF语句必须成对出现,且各占一行。

[ 例 7-9] 设出租车不超过 3公里时一律收费 7元钱,超过时则超过部分每公里加收 2.6元。试根据里程数编程计算并显示出应付车费。程序如下:CLEARINPUT "请输入里程数: " TO lcIF lc<=3 cf=7ELSE cf=7+(lc-3)*2.6ENDIF?" 车费为: ",cfRETURN

例题 7-10和 MESSAGEBOX函数同学们自学。

Page 17: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构

7.2.2 选择结构3. 分支嵌套结构 对于在上述分支结构中的 < 命令序列 > ,可以包含任何Visual FoxPro命令语句,也可以包括另外一个或几个合法的分支结构语句,也就是说分支结构可以嵌套。对于嵌套的分支结构语句,一定注意内外层分支结构层次分明,即注意各个层次的 IF...... ELSE......ENDIF语句配对情况。

[ 例 7-11] 永立公司对销售人员的报酬计算方法如下:每月销售 10万元(含 10万元)以下者,只得基本工资 1000 元;每月销售 10万元以上至 30万元(含 30万元)者,则超过 10万元以上部分按 2%提成;每月销售 30万至 50万(含 50万元)者,超过 30万元部分按 5%提成;超过 50万元部分按10%提成。以上各个级别的计算实行累加计算。编程按输入每个销售人员编号和销售额,计算每个销售人员的报酬(报酬结果按四舍五入规则取整)。编程思路:为了编程方便,先将每个级别的基准报酬计算出来,再根据销售额的多少用嵌套分支结构判断计算。该程序编写如下: CLEARACCEPT "销售员编号: " TO salenumberINPUT "销售额: " TO salevolume

pay1=1000pay2=pay1+ROUND((300000-100000)*0.02,0)pay3=pay2+ROUND((500000-300000)*0.05,0)IF salevolume<=100000 pays=pay1ELSE IF salevolume<=300000 pays=pay1+ROUND((salevolume-100000)*0.02,0) ELSE IF salevolume<=500000 pays=pay2+ROUND((salevolume-300000)*0.05,0) ELSE pays=pay3+ROUND((salevolume-500000)*0.1,0) ENDIF ENDIFENDIF?salenumber+"号销售员工作报酬: "+STR(pays,6,0)RETURN

Page 18: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构

7.2.2 选择结构4. 多分支选择结构虽然上述的分支嵌套结构可以解决程序设计中的多重选择问题,但当嵌套的层数较深时,则往往会引起结构的混乱,也使程序的可读性不好。 Visual FoxPro提供了多分支结构来解决多种不同情况下的程序选择问题。格式:DO CASE CASE <条件 1> < 命令序列 1> CASE <条件 2> < 命令序列 2> ...... CASE <条件 n> < 命令序列 n> [OTHERWISE < 命令序列 n+1>]ENDCASE

说明:a. 多分支选择结构执行的过程是:系统依次判断各 <条件 > 是否满足,若某一 <条件 >为 .T. ,就执行该 <条件 > 下的 < 命令序列> ,执行后不再判断其它 <条件 > ,而转去执行 ENDCASE后面的第一条命令。如果没有一个 <条件 > 为 .T. ,就执行 OTHERWISE后面的 [ 命令序列 ] ,直到 ENDCASE;如果没有 OTHERWISE,则不作任何操作就转向ENDCASE之后的第一条命令。b. DO CASE语句和 ENDCASE语句必须成对出现,各占一行。c. 多分支选择结构中各 CASE语句后的 <条件 > 是按其先后顺序判断执行的,因此对实际问题进行编程时,应认真考虑各个条件排列的先后顺序。

Page 19: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构

4. 多分支选择结构举例:将例 7-11 用多分支选择结构求解出来。左面蓝色程序代码为分支嵌套程序,右面红色程序代码为多分支选择结构程序代码。CLEARACCEPT "销售员编号: " TO salenumberINPUT "销售额: " TO salevolumepay1=1000pay2=pay1+ROUND((300000-100000)*0.02,0)pay3=pay2+ROUND((500000-300000)*0.05,0)IF salevolume<=100000 pays=pay1ELSE IF salevolume<=300000 pays=pay1+ROUND((salevolume-100000)*0.02,0) ELSE IF salevolume<=500000 pays=pay2+ROUND((salevolume-300000)*0.05,0) ELSE pays=pay3+ROUND((salevolume-500000)*0.1,0) ENDIF ENDIFENDIF?salenumber+"号销售员工作报酬: "+STR(pays,6,0)RETURN

CLEARACCEPT "销售员编号: " TO salenumberINPUT "销售额: " TO salevolumepay1=1000pay2=pay1+ROUND((300000-100000)*0.02,0)pay3=pay2+ROUND((500000-300000)*0.05,0)DO CASE CASE salevolume<=100000 pays=pay1 CASE salevolume<=300000 pays=pay1+ROUND((salevolume-100000)*0.02,0) CASE salevolume<=500000 pays=pay2+ROUND((salevolume-300000)*0.05,0) OTHERWISE pays=pay3+ROUND((salevolume-500000)*0.1,0)ENDCASE?salenumber+"号销售员工作报酬: "+STR(pays,6,0)RETURN

由此可见,利用多分枝选择结构编程比分支嵌套结构编程清晰、简单。

Page 20: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构

7.2.3 循环结构 在程序设计中,有时需要从某处开始有规律地反复执行某些类似的操作,这些类似的操作一般用循环结构程序设计来解决。在 Visual FoxPro中,提供了“当型”、“步长型”和“表扫描型”循环结构。

1. 当型循环结构格式: DO WHILE <条件> [ 命令序列 ] ENDDO

说明:a. 当型循环执行的过程是:根据 <条件 > 的逻辑值,进行判断。如果<条件 > 的逻辑值为 .T. ,则执行 DO WHILE和 ENDDO 之间的 [ 命令序列 ] ,当 [ 命令序列 ]包含的所有命令执行完毕后,程序自动返回到DO WHILE 语句,每执行一遍就判断一次 DO WHILE 语句中的 <条件> 。如果 <条件 >仍然为 .T. ,则继续执行 DO WHILE和 ENDDO 之间的 [ 命令序列 ] ,直到 <条件 > 的逻辑值为 .F. ,则跳过 DO WHILE和 ENDDO 之间的 [ 命令序列 ] ,结束循环,转去执行 ENDDO 之后的第一条命令。b. DO WHILE和 ENDDO语句应配对使用,各占一行。c. 在 [ 命令序列 ] 的适当位置可以放置EXIT 和 LOOP语句,用以对循环过程作特殊处理。 EXIT 的功能是:终止本层循环命令。 LOOP语句的功能是:终止本次循环命令。 EXIT 和 LOOP语句只能在循环结构中使用,一般情况下与 IF......ENDIF等分支结构配合使用。d. 在命令序列中可以嵌套 IF……ENDIF、 DO CASE……ENDCASE、DO WHILE……ENDDO、 FOR……ENDFOR、SCAN……ENDSCAN等程序结构。

Page 21: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构

7.2.3 循环结构[ 例 7-13] 有一张厚 0.5毫米,面积足够大的纸,将它不断地对折。问对折多少次后,其厚度可达到珠穆朗玛峰的高度( 8848米)。 问题分析:设对折的次数为 n,纸张的厚度为 h,每次对折都是上次厚度的 2倍(为 2*h,将它再赋值给 h),然后用此厚度与珠穆朗玛峰的高度作比较,每次循环进行一次加 1 计算(即 n+1 ,将 n+1 再赋值给n),以便统计对折的次数,当纸张厚度大于等于 8848米时停止循环,该程序流程图如图 7-15所示。根据分析,程序为:

CLEARn=0h=0.5DO WHILE h<8848000 n=n+1 h=2*hENDDO?"对折的次数为: ",n?" 此时纸张的厚度为: ",hRETURN

图 7-15 例 7-13 程序框图

Page 22: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构

[ 例 7-14] 鸡兔同笼问题。设鸡和兔共有头 38个,脚 138个,问鸡和兔各为多少只?

问题分析:设鸡为 cocks只,兔为 rabbits只,则有: cocks+rabbits=38;2*cocks+4*rabbits=138。可令鸡和兔的头数之和或者脚数之和为一变量,如本题令二者脚数之和 foots 为变量,开始令 cocks=0, foots=0,用循环进行判断是否 foots<>138,如果是,则进行如下运算: cocks=cocks+1 ; rabbits=38-cocks ; foots=2*cocks+4*rabbits ;再进行循环判断,直到 foots<>138不成立(即 foots=138),循环结束。输出结果。程序如右面红色代码 :

CLEARcocks=0foots=0DO WHILE foots<>138 cocks=cocks+1 rabbits=38-cocks foots=2*cocks+4*rabbitsENDDO?"鸡的数量为: ",cocks?"兔的数量为: ",rabbitsRETURN

例题 7-15自学

Page 23: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构

7.2.3 循环结构2. 步长型循环结构格式:FOR <循环变量 >=<初值 > TO <终值 > [STEP < 步长值 >] [ 命令序列 ] &&[ 命令序列 ]也称为循环体ENDFOR|NEXT

说明:a. <初值 >、 <终值 >、 < 步长值 >都是数值表达式;当 < 步长值 > 是 1时,可以省略 STEP子句。b. ENDFOR 或 NEXT语句为循环终端语句,用以标明本循环结构的终点。该语句必须和 FOR语句配对使用。c. 该循环结构的执行过程是:首先将初值赋值给循环变量,然后判断循环变量的值是否超过终值(这里超过终值的含义是:如果步长值为正数,则循环变量的值大于终值为超过,如果步长值为负数,则循环变量的值小于终值为超过),不超过就执行循环体,遇到 ENDFOR 或 NEXT语句,自动使循环变量增加一个步长值,再将循环变量的值与终值比较,如果循环变量的值不超过终值,就再执行循环体,不断循环执行。如果循环变量的值超过终值则不执行循环体,而转去执行 ENDFOR 或 NEXT语句后面的第一条语句。d. 在循环体内的适当位置也可以放置EXIT 和 LOOP语句,作用和用法与当型循环结构类似。

Page 24: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构

7.2.3 循环结构[ 例 7-16] 求 1+2+3+…+99+100的值。 问题分析:采用累加的办法,用循环变量产生 1、 2、 3、…、 99、 100这些数。用 s保存累加和, s 的初始值为 0,每次循环将 s加上循环变量的值,再赋值给变量 s ,循环结束即求得S。程序为:

CLEARs=0FOR x=1 TO 100 s=s+xENDFOR?"1--100自然数累加和是: ",sRETURN

Page 25: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构

7.2.3 循环结构[ 例 7-17] 从键盘上输入任何一个自然数,求该自然数的阶乘。保存文件名为 cx17a 。问题分析:假设该自然数为 n,那么求 n的阶乘的公式是: n*(n-1)*(n-2)*......*2*1有了这样的公式,我们就可以用循环程序将该自然数 n的阶乘求解出来。将循环变量的初值设为 n,终值设为 1 ,步长值设为 -1 。用 factor 作为存放阶乘的变量, factor 的初始值为 1 ,每次循环都使 factor 乘以循环变量的值,循环结束即求得 factor 的值。该程序如下:

CLEARfactor=1INPUT "请输入一个自然数: " TO nFOR x=n TO 1 STEP -1 factor=factor*xENDFOR?"自然数 "+ALLTRIM(STR(n,10))+"的阶乘是: "+ALLTRIM(STR(factor,20))RETURN

本题的其他方法请同学自学

Page 26: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构

7.2.3 循环结构3、表扫描循环结构格式: SCAN [< 范围 >][FOR <条件 1> |WHILE <条件 2>] 命令序列 ] &&[ 命令序列 ]也称为循环体 ENDSCAN 说明:a. 该结构是针对当前打开的数据表进行操作的。它的功能是:对当前打开的数据表

中指定范围内符合条件的记录,逐个进行 < 命令序列 > 所规定的操作,如果缺省范围和条件子句时,则对所有记录逐个进行 < 命令序列 >规定的操作。

b. 表扫描型循环结构每循环一遍,记录指针自动移动到下一条记录,不需要设置SKIP语句。

c. SCAN 和 ENDSCAN语句要配对使用。d. 在 < 命令序列 > 的适当位置也可以放置EXIT 和 LOOP语句,功能和用法同其他循环结构类似。

Page 27: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构

7.2.3 循环结构[ 例 7-18] 将人事数据表中基本工资小于 1000的姓名、基本工资两个字段输出,并统计这些职工的人数。 基本操作步骤为:关闭所有数据表(可选步骤),打开人事数据表,设计一个累加变量 n,代表满足条件的记录数,给n 赋初值 0,用表扫描循环结构定位满足条件的记录,输出姓名、基本工资两个字段,并对 n 进行累加 1 ,循环结束即求得n,输出n。程序如下:

CLOSE DATABASECLEARUSE rsbn=0SCAN FOR 基本工资 <1000 ?姓名 ,基本工资 n=n+1ENDSCAN ?"基本工资在 1000元以下的人数有: "+STR(N,2)+" 人。 "CLOSE DATABASERETURN

Page 28: 第 7 章   程序设计

第 7 章 程序设计7.2 程序的控制结构7.2.3 循环结构

4、循环结构嵌套 循环结构的嵌套是指在一个循环体内包含其他的循环结构,也称为多重循环结构。同一种类型的循环结构可以嵌套,不同类型的循环结构也可以嵌套。要编好循环嵌套结构程序,必须做到:循环开始语句和循环结束语句配对出现;内外层循环层次分明,不得交叉。 Visual FoxPro 最多允许 128层嵌套。

[ 例 7-19] 用双重循环打印九九乘法表,即:1×1=1 , 1×2=2 ,…, 1×9=92×1=2 , 2×2=4 ,…, 2×9=18...... ...... ......9×1=9, 9×2=18,…, 9×9=81

问题分析:这是一个有 9个行、 9个列数据项的矩阵,可以用双重循环解决。外循环用于控制各个行,内循环用于控制每一行的各个列项,一行输出完毕以后,换行输出下一行各个列的数据项。程序如下:

* 打印乘法九九表。CLEARFOR a=1 TO 9 FOR b=1 TO 9 p=a*b ??STR(a,1)+"×"+STR(b,1)+"="+STR(p,2)+" " ENDFOR?ENDFORRETURN

Page 29: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

应用程序一般都是多模块程序,可包含多个程序模块。模块是可以命名的一个程序段,可指主程序、子程序、函数、过程。

7.3.1 子程序 能够完成一定功能的可供其它程序使用(调用)的独立程序段称为子程序。它独立存在,但可以被多次调用,调用子程序的程序称为主程序。在应用系统开发中,把程序完成的主要功能都分配给各子程序去完成,这样主程序可以写得比较简捷,整个应用系统的维护方便,应用系统运行的效率也很高。

1、子程序的调用格式: DO < 程序文件名 1>[with < 参数表 >][IN < 程序文件名 2>]说明:a. 程序文件名 1 :指定要执行程序的名字。 DO < 程序文件名 1> 直接执行或调用 < 程序文件名 1> 指定的程序。b. [WITH < 参数表 >] :指定传递到子程序的参数,在 < 参数表 > 中列出的参数可以是表达式、内存变量、常量、字段或用户自定义函数。c. 当 < 程序文件名 1> 是子句 IN < 程序文件名 2> 中的一个过程时, DO 命令调用该过程,请参阅 [ 例 7-26] 。

Page 30: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

7.3.1 子程序2、子程序的返回 RETURN [TO MASTER |TO < 程序文件名 >]说明:a. 该语句放在一个程序的末尾。b. 不带参数的 RETURN语句的功能是将程序控制权返回到调用该子程序的主程序的

下一条命令语句。c. RETURN TO MASTER :如果有多级程序调用,某一子程序的该语句将使程序控制权返回到最高一级调用程序。

d. RETURN TO < 程序文件名 > :表示将控制权交给指定的程序。

3、子程序的建立 建立子程序的方法与以前我们建立程序的方法类似。但要注意两个问题,一是每个子程序必须单独使用一个文件名保存起来,二是主程序和子程序之间有关变量值的传递关系。子程序文件名的扩展名也是 .PRG 。

Page 31: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序7.3.1 子程序

[ 例 7-21] 利用主程序调用子程序的方法计算任意 3 个自然数的阶乘和,即求 s=a!+b!+c! 建立步骤:先建立好求任一自然数阶乘的程序,如 [ 例 7-17] 。由于这里是通过主程序调用子程序的方法求三个自然数阶乘之和,因此在子程序中所求出的每个自然数的阶乘就不用输出了;另外子程序计算所需的自然数是主程序通过变量传递到子程序的,因此,在子程序中输入自然数的语句也可以不要。所以,在本例中,作为求阶乘的子程序可以是如下的程序代码:

factor=1FOR x=n TO 1 STEP -1 factor=factor*xENDFORRETURN 注意,该子程序中的变量 n的值需要由主程序传递。将该子程序保存文件名为: jc 调用该子程序的主程序为:CLEARINPUT "a=" to aINPUT "b=" to bINPUT "c=" to c

s=0 &&定义存放阶乘的累加和的变量factor=1 &&定义与子程序传递阶乘计算结果的变量n=a &&定义计算阶乘需要自然数的传递变量DO jcs=factorn=bDO jcs=s+factorn=cDO jcs=s+factor?ALLTRIM(STR(a,3))+“!”+ALLTRIM(STR(b,3))+“!”+; ALLTRIM(STR(c,3))+"!=",sRETURN

Page 32: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

7.3.2 自定义函数 Visual FoxPro提供了许多系统函数,用户也可以自己定义函数(User Defined Function ),简称UDF 。 UDF 与内部函数一样,可以在程序、命令窗口或函数嵌套中使用。在 Visual FoxPro中有两种形式的 UDF :独立 UDF 和依附 UDF 。

1、独立用户定义函数实际上独立用户定义函数就是带参数传递的子程序,差别仅仅是用户定义函数的最后一条 RETUR

N语句后有表达式、以及调用的方式不同。用户定义函数用如下格式定义。格式: [PARAMETERS < 参数表 >] [ 命令序列 ] RETURN [< 表达式 >]说明: a. [PARAMETERS < 参数表 >] :接受函数运行时传递过来的数据,如果函数不需要传递数

据,该语句可省略。b. [ 命令序列 ] :用于进行各种处理的命令组合。简单的函数也可以为空。c. RETURN < 表达式 >语句中 < 表达式 > 的值作为返回函数值,它决定了函数的类型。如缺省该语句,则返回函数值为 .T. 。

d. 函数名称就是保存时用的程序文件名。如果 UDF 的名称与已有的函数名相同,系统只承认已有函数,因此不能用已有的函数名来命名 UDF 。

e. UDF 的调用形式是 <函数名 >( [< 参数表 >])。

Page 33: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

7.3.2 自定义函数1、独立用户定义函数[ 例 7-23] :定义一个计算求立方数的函数。

( 1)创建函数求立方数函数。函数名为cube( 即以 cube.prg 为文件名存盘 ) 。

PARAMETERS v RETURN v*v*v

下面程序中调用求立方函数 cube.prg,求 1 到10的立方数。

( 2)在程序中调用函数* 求 1 到 10的立方数。程序名为 CX23CLEARFOR i=1 TO 10 ?i,cube(i)ENDFORRETURN

自定义函数 cube 不仅可以在程序中调用,也可以命令窗口里调用。

Page 34: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

7.3.2 自定义函数2、依附用户定义函数 依附用户定义函数不能作为一个独立的程序文件,它以 FUNCTION<函数名 > 开头,依附在某程序的后面、某过程文件中。依附用户定义函数用如下格式定义。格式: FUNCTION <函数名 > [PARAMETERS < 内存变量表>] [ 命令序列 ] RETURN [< 表达式 >]说明:FUNCTION <函数名 > 在程序里标识 UDF 的开始并定义函数名。其他与独立函数规定相同

[ 例 7-24] 用依附定义函数编写求 1--10的立方数。* 求 1 到 10的立方数。CLEARFOR i=1 TO 10 ?i,cube1(i)ENDFORRETURN

FUNCTION cube1PARAMETERS vRETURN v*v*v

例题 7-25自学

Page 35: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

7.3.3 过程 把多个子程序合并成一个大的文件,在该文件中,每个子程序仍然是独立的,这个大的公用程序文件被称作过程文件,其中的每个子程序模块成为过程。由于过程文件是集中起来以一个文件的形式存储在磁盘上的,调用时作为一个文件一次打开,每个子过程可随时调用,从而大大减少了访问磁盘的次数,可提高程序运行效率。过程用如下命令格式建立。格式: PROCEDURE < 过程名 > [PARAMETERS < 参数表 >] < 命令序列 > RETURN说明:a. 过程是以 PROCEDURE开头,并标识出 < 过程名 > 的程序或程序段,指定生成过程的名称, < 命令序列 > 是过程体,用 DO < 过程名 > 命令调用。b. 过程可以放在主程序的后面,由主程序调用。c. 可以将一个或多个过程组织在一个程序文件中,需要时分别调用。

Page 36: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

7.3.3 过程[ 例 7-26] 过程跟在主程序后面举例。用主程序调用过程的方式编程求圆面积、圆周长、球体积。

* 主程序CLEARINPUT "请输入半径: " TO radiusmj=0zc=0tj=0DO ymj WITH mj,radiusDO yzc WITH zc,radiusDO qtj WITH tj,radius?" 半径为 "+alltrim(str(radius,10))+"的圆面积是: ",mj?" 半径为 "+alltrim(str(radius,10))+"的圆周长是: ",zc?" 半径为 "+alltrim(str(radius,10))+"的球体积是: ",tjRETURN

* 过程PROCEDURE ymjPARAMETERS s,rs=pi()*r^2RETURN

PROCEDURE yzcPARAMETERS s,rs=2*pi()*rRETURN

PROCEDURE qtjPARAMETERS s,rs=4/3*pi()*r^3RETURN

Page 37: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

7.3.3 过程[ 例 7-27] 过程文件调用举例。在主程序中调用过程文件中过程的方式编程求圆面积、圆周长、球体积。

可以将 [ 例 7-26] 中三个子过程组合成一个过程文件,假设文件名为: circle 。它包括如下内容:

* 过程文件,文件名为 CIRCLEPROCEDURE ymjPARAMETERS s,rs=pi()*r^2RETURNPROCEDURE yzcPARAMETERS s,rs=2*pi()*rRETURNPROCEDURE qtjPARAMETERS s,rs=4/3*pi()*r^3RETURN

* 主程序CLEARINPUT "请输入半径: " TO radiusmj=0zc=0tj=0DO ymj WITH mj,radius IN circle &&表明过程 ymj在过程文件 circle中DO yzc WITH zc,radius IN circle &&表明过程 yzc 在过程文件 circle 中DO qtj WITH tj,radius IN circle &&表明过程 qtj在过程文件 circle 中?" 半径为 "+alltrim(str(radius,10))+"的圆面积是: ",mj?" 半径为 "+alltrim(str(radius,10))+"的圆周长是: ",zc?" 半径为 "+alltrim(str(radius,10))+"的球体积是: ",tjRETURN

例题 7-27 方法二自学

Page 38: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

7.3.4 变量的作用域 在多模块程序中,根据变量的发生作用的范围,可将变量分为公共变量、私有变量和本地变量 3 类。

1、公共变量 在任何模块中都能使用的变量称为公共变量,也称为全局变量。当某些变量需要在各个模块中都可能发挥作用的时候,要定义成公共变量。用下列格式定义变量为公共变量。格式: PUBLIC < 内存变量表 >说明:a. 将 < 内存变量表 > 指定的所有变量定义为公共变量。b. 在命令窗口里定义的变量都是公共变量。c. 程序终止时,公共变量不会自动清除,需要用 CLEAR ALL或者 RELEASE ALL命令清除。d. 可以用类似的格式将数组建立并声明为全局数组,如下列命令。PUBLIC [ARRAY]< 数组名 >(< 数值表达式 1>[,< 数值表达式 2>])[,< 数组名 >(< 数值表达式 1>[< 数值表达式 2>]),…]

Page 39: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

7.3.4 变量的作用域2、私有变量 程序中使用的内存变量,凡未经特殊说明的均属于私有变量,这些内存变量可以在本级程序及以下各级子程序中使用,其值可以在子程序中改变,返回主程序时保留改变后的值。 如果在某一级模块中使用的变量名称可能与上级模块使用的变量名称一样,而这些变量返回到上级模块时,又不想让子程序中变量值影响上级模块中同名变量的值, Visual FoxPro提供了屏蔽上级模块变量的方法,被屏蔽的变量名,当子程序结束返回到主程序时,不会影响主程序中同名变量的值。下述声明私有变量的命令就能起到屏蔽上级同名变量的作用。格式:PRIVATE < 内存变量表 >|[ALL [LIKE|EXCEPT < 通配符 >]]说明:a. 声明的私有变量,只能在当前以及下级程序中有效,当本级程序结束返回上级程序时,私有变量自动清除,主程序中同名变量恢复其原来的值。b. 在程序模块调用时, PARAMETERS < 参数表 > 语句中 < 参数表 > 指定的变量自动声明为私有变量。

Page 40: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

7.3.4 变量的作用域

3、本地变量 本地变量既不能在上级模块中发挥作用,也不能在下级模块中发挥作用,只能在建立它的模块中发挥作用,本级模块结束,本地变量自动清除。下列命令将变量声明为本地变量。格式: LOCAL < 内存变量表 >LOCAL将 < 内存变量表 > 指定的变量声明为本地变量,并赋初值为 .F. 。注意, LOCAL不能简写为 LOCA(Visual FoxPro认为 LOCA 与 LOCATE具有同样的含义)。

Page 41: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

7.3.4 变量的作用域[ 例 7-28] 变量作用域举例。认真分析如下程序中变量发生作用的范围。* 主程序 cx28.prgCLEARCLEAR ALLa1=10a2=10a3=10LIST MEMO LIKE a?do cx28zcx1LIST MEMO LIKE a?CLEAR ALLRETURN

*子程序 cx28zcx1.prgPRIVATE a1LOCAL a2a1=5a2=5LIST MEMO LIKE a?DO cx28zcx2LIST MEMO LIKE a?RETURN

*子程序 cx28zcx2.prgPUBLIC a4a4=20LIST MEMO LIKE a?RETURN

Page 42: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

7.3.5 结构化模块程序设计 一个应用系统通常有多个模块系统组成,通常用菜单系统来管理它们。下面介绍一个用结构化程序设计方法编写应用系统的例子。

[ 例 7-29] 编写一个应用程序,能够实现对人事数据表 rsb 进行修改、查询、打印数据表数据并具有选择退出功能。问题分析:我们采用主程序调用子程序的方法解决该问题,因此先建立好各个子程序,这里我们采用 [ 例 7-15] 设计的程序作为对数据表进行修改的子程序,采用 [ 例 7-20] 作为对数据表进行查询的子程序,用 LIST 命令实现数据表数据列表送到打印机打印输出;按题目功能要求,建立一个选择菜单显示在屏幕上,每一菜单项目代表一种功能选择,选择相应的菜单项目就执行相应的子程序或命令,按“退出”菜单项,退出应用系统。下面程序可实现上面的功能要求。

Page 43: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

CLEARTEXT&&TEXT......ENDTEXT 之间的内容可以在屏幕上原样显示,作为本程序的菜单提示。* * * * * * * * * * * * * * * * * * * * ** 1. 数据修改 2. 数据查询 ** 3. 打印数据 4. 系统退出 ** * * * * * * * * * * * * * * * * * * * *ENDTEXTDO WHILE .t. @5,8 SAY "请选择 1-4 : " GET number DEFAULT SPACE(1) READ DO CASE CASE number="1" DO cx15 &&[ 例 -15] 程序 CASE number="2" DO cx20 &&[ 例 -20] 程序 CASE number="3" USE rsb LIST TO PRINTER USE CASE number="4" WAIT "系统将在 8 秒内自动关闭 !" WINDOWS AT 20,18 TIMEOUT 8 EXIT ENDCASEENDDOCLEARRETURN

Page 44: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

7.3.6 程序的调试 在开发应用程序时,为了保证程序的正确性和合理性,需要对应用程序进行调试,以发现其中的错误并进行修改,直至达到设计要求,才能投入使用。 1、程序中常见的错误 程序中常见的错误包括语法错误、溢出错误、逻辑错误。语法错误包括命令字拼写错误、命令格式错误、使用了中文标点符号作为分界符、使用了没有定义的变量、数据类型不匹配、操作的文件不存在等;溢出错误包括计算结果超过 Visual FoxPro所允许的最大值、文件太大、嵌套层数超过允许范围等;逻辑错误指程序设计的差错,如要计算圆的面积,在程序中却用了计算圆周长的公式等。对于语法错误和溢出错误可以通过运行程序,系统给出相应提示信息予以纠正;对于逻辑错误,只有通过运用典型数据进行测试,分析计算结果是否合理和正确,才能予以纠正。 2、程序查错 查错技术可分为两类:一类是静态检查,例如通过阅读程序寻找错误;另一类是动态检查,即通过运行程序来检查运行结果是否正确、是否符合要求。动态检查有如下方法。 ( 1)使用出错信息( 2)调试器( 3)错误处理程序

Page 45: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

7.3.6 程序的调试2、程序查错( 3)错误处理程序 ON ERROR 命令用来当程序出现错误时指定执行的程序,可以帮助我们定位错误和提供相关信息。格式: ON ERROR <COMMAND> 这里, COMMAND 是指定程序出错时应执行的 Visual FoxPro命令。执行此命令后,程序将从引起错误的程序行的下一行重新开始执行。但如果错误处理过程中包含 RETRY ,则重新执行引起错误的程序行。

例 7-31] 编写一个能将任意数据表文件复制到 A盘的程序,在进行复制之前用信息对话框给出提示信息“请将磁盘插入驱动器 A 中,按确定按钮复制,按取消按钮退出”;若驱动器未准备好可以允许重试 3次,同时在一个信息对话框中显示错误代码、错误消息、错误程序名称、错误行号并提示解决措施。该程序代码如下:

Page 46: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

CLEARON ERROR DO errorhandling WITH ERROR(),MESSAGE(),LINENO(),PROGRAM() i=1 &&i为重试次数变量@6,8 SAY "请输入数据表文件名: " GET tablename DEFAULT SPACE(8)READtablename=ALLTRIM(tablename)IF FILE("&tablename..dbf") use &tablename x=MESSAGEBOX("请将磁盘插入驱动器 A 中,按确定按钮复制,按取消按钮退出 ",1+48; +256,“ 复制文件 ") &&当按确定按钮时,函数返回 1给 x,按取消按钮时函数返回 2给 x。 DO CASE CASE x=1 WAIT "正在复制 ..." WINDOWS AT 18,50 NOWAIT COPY TO a:&tablename &&如果 A驱动器没有准备好,该语句会出错 CASE x=2 WAIT "不复制退出! " WINDOWS AT 18,50 ENDCASEELSE WAIT " 该文件不存在! " WINDOWS AT 18,50ENDIFCLEARRETURN

Page 47: 第 7 章   程序设计

第 7 章 程序设计7.3 多模块程序

PROCEDURE errorhandlingPARAMETERS errorcode,messagename,errorline,programnametem="错误代码: "+STR(errorcode)+CHR(13) &&CHR(13) 相当于按回车健,表示换行tem=tem+"错误消息: "+messagename+CHR(13)tem=tem+"错误程序: "+programname+CHR(13)tem=tem+"错误行号: "+STR(errorline)+CHR(13)=MESSAGEBOX(tem+"驱动器没有准备好,请将磁盘插入到 A驱动器中。 ",0+48+0,"复制文件 ")i=i+1IF i<=3 RETRYENDIFCLEARRETURN

Page 48: 第 7 章   程序设计

第 7 章 程序设计7.4 数组应用

7.4.1 常用数组函数介绍 1、 ALEN函数格式:ALEN(ArrayName[,nArrayAttribute])功能:返回数组元素的个数,行或列。说明: a. ArrayName 为数组的名称。如果数组是一维数组,则该函数返回数组元素的个数,假设有数组 x(10) ,则函数 ALEN(x) 的返回值是 10。b. nArrayAttribute 参数是指二维数组的行或者列,它的取值为 1、 2 或者0。取值为 1时,返回该数组的行数;为 2时,返回该数组的列数;为 0或省略该参数时,返回二维数组的元素的数量。假设有二维数组 x(6,8) ,那么 ALEN(x,1)返回值为 6, ALEN(x,2)返回值为 8, ALEN(x,0) 或 ALEN(x)返回值为 48。 2、 ASORT函数格式:ASORT( ArrayName[,nStartElement[,nNumberSorted[,nSortOrder]]])功能:将数组元素的值按要求排序,将排序好的值写回数组。说明: a. ArrayName 指要排序的数组名; nStartElement指数组元素要参与排序的起始元素,该数值不能超过数组元素的最大值,否则将出现下标超界错误,该参数缺省指从数组元素的第一个开始排序; nNumberSorted 指要参与排序的数组元素的数量; nSortOrder 指排序的规则,该值大于等于 1时按降序排,小于 1时按升序排,缺省时按升序排。如 ASORT(x) 按升序重新排列 x数组中各个元素并写回数组; ASORT(x,2,8,1)函数将数组 x的元素从第 2 个元素开始排序,参与排序的数组元素的数量是 8个,降序排,其他没有包括在此范围的数组元素保持原来的顺序。b. 该函数正确执行后将返回数值 1 。

Page 49: 第 7 章   程序设计

第 7 章 程序设计7.4 数组应用

7.4.2 数组与数据表之间数据的传递 和 7.4.3 数组其他应用举例 的“ 1、数组参数与过程、函数的数据传送举例 ”部分 自学

7.4.3 数组其他应用举例2、算法举例[ 例 7-36] 排序问题。在程序运行时,从键盘输入任意 10个自然数给数组,将这 10个数从小到大重新排序后输出。 问题分析:该问题分为三个部分。第一部分是将数据输入到一个数组中,比较简单,用一个单重循环加上屏幕数据输入语句即可完成。第二部分是数据处理部分,也就是要对数组中的数据重新排序,我们可以采取如下方法:将数组中的第一个元素与后面的每一个元素进行比较,如果某一个元素的值比第一个元素的值小,则交换二者的值,一直比较到最后一个元素,则第一个元素就是数组中元素的最小值;再将数组中第二个元素与后面的每一个元素进行比较,如果某一个元素的值比第二个元素的值小,则交换二者的值,一直比较到最后一个元素,则第二个元素就是数组中所有元素第二最小值元素;依此类推,一直进行到数组中倒数第二个元素与倒数第一个元素比较完毕,则数组元素排序完成。这种方法称为“冒泡法”,可用二重循环解决。第三部分是输出部分,可用一个单重循环解决。根据以上分析,程序代码为:

Page 50: 第 7 章   程序设计

第 7 章 程序设计7.4 数组应用CLEAR

DIMENSION x(10)* 数据输入部分FOR i=1 TO 10 x(i)=0 @3,8 SAY "请输入第 "+ALLTRIM(STR(i,2))+"个数据: " GET x(i) READENDFORCLEAR@5,8 SAY " 排序之前数组各元素的值是: "FOR i=1 TO 10 @5+i,8 SAY x(i)ENDFOR* 数据处理部分FOR i=1 TO 9 FOR j=i+1 TO 10 IF x(j)<x(i) a=x(i) x(i)=x(j) x(j)=a ENDIF ENDFORENDFOR

*排序后数据输出部分@16,8 SAY " 排序之后数组各元素的值是: "FOR i=1 TO 10@16+i,8 SAY x(i)ENDFORRETURN

请大家思考如何用函数 ASORT(x,1,10,0)或 ASORT(x)来代替本程序中的数据处理部分。