第 5 章 程序设计基础
DESCRIPTION
第 5 章 程序设计基础. Visual FoxPro 不仅是一个功能很强的 数据库管理系统,而且还内含一个使用方 便、功能强大的应用程序开发工具。本章 主要介绍程序设计的基础知识,包括结构 化程序设计的基本方法和面向对象程序设 计中的基本概念。. 5.1 程序设计概述. 程序设计 ( Programming )是利用系统所提供的设计 工具,按照程序设计语言的规范描述解决问题的算法并进行 程序编写的过程。 这个过程应包含分析、设计、编码、测试和排错等不同 阶段。 程序设计两种方法: - PowerPoint PPT PresentationTRANSCRIPT
第 5 章 程序设计基础
Visual FoxPro 不仅是一个功能很强的数据库管理系统,而且还内含一个使用方便、功能强大的应用程序开发工具。本章主要介绍程序设计的基础知识,包括结构化程序设计的基本方法和面向对象程序设计中的基本概念。
5.1 程序设计概述 程序设计( Programming )是利用系统所提供的设计工具,按照程序设计语言的规范描述解决问题的算法并进行程序编写的过程。 这个过程应包含分析、设计、编码、测试和排错等不同阶段。程序设计两种方法:结构化程序设计( Structured Programming , SP )面向对象的程序设计( Object-oriented Programming , OOP )从程序设计的方法来看: Visual FoxPro 既支持结构化程序设计,也支持面向对象程序设计,并提供了许多相关的可视化开发工具。
结构化程序设计( Structured Programming , SP )
提出时间: 20 世纪 60 年代主要思想(程序遵循的设计原则): 自顶向下 逐步求精 模块化 限制使用转移语句程序流程三种基本结构:顺序、分支、循环。本质:功能设计方法:自顶向下,功能分解开发过程:从“做什么”到“如何做”
面向对象的程序设计( Object-oriented Programming , OOP )
提出时间: 20 世纪 60 年代,但发展缓慢, 20 世纪 90 年代,面向
对象的程序设计方法风靡了整个软件行业,出现了大量支持面向对象程序设计的语言和开发工具。基本思想:世界由各种对象,任何事物都是对象,是某个对象类的实例,复杂的对象可有较简单的对象组合而成。基石:对象和类 对象:数据及其作用于这些数据之上的操作结合在一起所构成
的独立实体的总称。 类:一组具有相同数据结构和相同操作的对象的描述。基本机制:方法和消息 消息:要求某个对象执行类中某个操作的规格说明 方法:对象所能执行的操作,它是类中定义的函数,描述对象
执行某个操作的算法,每个类都定义了一组方法。三个重要特性:封装性、继承性和多态性。
面向对象的程序设计( Object-oriented Programming , OOP )
三个重要特性:封装性、继承性和多态性。 封装性:是指对象是数据和处理该数据的方法所构成的整体,外界
只能看到其外部特性(消息模式、处理能力等),其内部特性(私有数据、处理方法等)对外部不可见。
继承性:反映的是类与类之间不同的抽象级别,根据继承与被继承的关系,类可分为基类(父类)和衍生类(子类)。子类可以从父类那里获得所有的属性和方法,并且可以对这些获得的属性和方法加以改造,使之具有自己的特点。
多态性:在形式上表现为一个方法根据传递给它的参数的不同,可以调用不同的方法体,实现不同的操作。
解决过程:采用自底向上方法,先将问题空间划分为一系列对象的集合,再对对象集合进行分类抽象,一些具有相同属性行为的对象被抽象为一个类,类还抽象分为子类。其间采用继承来建立这些类之间之间的联系,形成结构层次。同时对于每个具体类的内部结构,又可采用自顶向下逐步细化的方法由粗到细精化之。
5.2 结构化程序设计 结构化程序设计是指根据不同的情况和条件,控制
程序去执行相应操作的语句序列。 Visual FoxPro 中有一类特殊的命令,在这些命令的控制下,可以使其他的一组命令或函数重复执行多次,或者根据一定的条件控制程序执行某一组命令而不执行另一组命令。 程序结构主要分为:顺序结构、分支结构、循环
结构,以及过程 / 函数调用,这些结构可以嵌套。
5.2.1 创建、修改和运行程序1.创建和修改程序文件 Visual FoxPro 程序是包含一系列命令的文本文件,其文件扩展名为 PRG 。三个步骤:
打开编辑窗口的方法:( 1 )
打开编辑窗口的方法三种:( 2 )
打开编辑窗口的方法三种:( 3 )
打开编辑窗口的方法三种:( 4 )
程序的修改
2.运行程序
在 Visual FoxPro中,一旦运行程序文件,系统会自动地对程序文件( .prg)进行编译(包括对程序的词法检查、语法检查),生成“伪编译”程序( .fxp)。执行程序时,系统实质上是执行 .fxp 文件。
例 1 :编写一个程序,保存并运行。
复习:名称表达式定义:是由圆括号括起来的一个字符表达式,可以用来替换命令和函数中的名称(字段名、变量名、窗口名、菜单名、文件名、对象名)格式:(内存变量名称)功能:可以用来替换命令和函数中的名称,从而为 VFP命令和函数提供了灵活性。
(1) 用名称表达式替换命令中的字段名
USE XSFLD1='XH'FLD2='XM'BROWSE FIELDS (FLD1),(FLD2)
(2) 用名称表达式替换命令中的变量名。
Nvar=100Var_name='nvar'Store 123.4 to (var_name)?nvar
结果 123.4
(3)用名称表达式替换命令中的表文件名
Dbf_name='js'Use (dbf_name)
(4) 用名称表达式作为函数的参数
String1='visual foxpro 6.0'str_var='string1'?substr((str_var),1,6)
结果: string
(5) 用字符串表达式来构成一个名称表达式
Db_name='jxsj'Dbf_name='js'Use(db_name+'!'+dbf_name)
(6) 名称表达式不能出现在赋值号左边
例:Var=[abc](var)=123
(7)宏替换格式: &字符内存变量功能:将存贮在字符型内存变量中的字符串替换出现,即把该变量所代表的字符串去掉定界符后重新放到该函数所在位置上。宏替换函数符号与内存变量名之间不能有空格,宏替换函数的范围是从符号“ &”起,直到遇到一个点号( . )或空白为止。
(7)宏替换nVar=100var_name='nvar‘store 123.4 to &var_name?nvar
123.4
名称表达式和宏替换的相同点
1.替换命令中的变量名Nvar=10var_name='nvar'Store 100 to (var_name) Store 100 to &var_name?nvar
2.替换命令中的文件名X='js'Close tables allUse &xUse (x)
5.宏替换与名称表达式的不同点
1 )宏替换可以连续替换,名称表达式则不行例:string1='visual foxpro'Str_var='string1'?substr(&str_var,1,6) &&visual?substr((str_var),1,6) &&string
5.宏替换与名称表达式的不同点
2 )宏替换可以出现在“ =”左边,而名称表达式则不行
1.当’ =’ 为赋值号时Var_name='cvar3'
&var_name='test2'
(var_name)='test2'
?&var_name
2. 当‘ =’ 为关系运算符时
Use xs
Field_name='xs.xm'
Locate for &field_name=' 李千里 '
Locate for (field_name)=' 李千里 '
5.宏替换与名称表达式的不同点
3)宏替换可以和其他符号直接相连,构成变量名,其结尾符号为点号( . ) , 而名称表达式不能和其他字符直接相连。Nvar=10Nvarb=50Xnvar=20var_name=‘nvar’Store 230.5 to &var_name.b?nvarbStore 100 to x&var_name?xnvar
5.宏替换与名称表达式的不同点
4)宏替换可以用于类型转换,而表达式不可以。这一点也可以理解为:宏替换可以构成表达式,而名称表达式则不可以。m=’25’?15+&m?15+(m)
5.宏替换与名称表达式的不同点
5)宏替换可以替换整条命令,而名称表达式不可以X=‘select xh,xm,xb from xs where xb=
‘女’’&x( x )
5.2.2 顺序结构
所谓顺序结构,是指程序运行时按照
语句排列的先后顺序,一条接一条地依次
执行,程序的执行流程如图 5-1 所示。A
B
图 5-1 顺序结构
例 5.1 下列程序的功能是计算圆的面积,其半径为 4.12。
STORE 4.12 TO PS=P*P*3.14?'圆面积为 :',S
例 5.2 下列程序的功能是显示一个字符串在另一个字符串中的位置。
C=‘Visual FoxPro’CC=‘Fox’?AT(CC,C)
例 3 执行下列命令后,被打开的表文件是:
X=‘xs.dbf/cj.dbf/js.dbf’L=AT(‘/’,X)+1F=SUBSTR(X,L,2)USE &F
5.2.3 分支结构 所谓分支结构,是指程序在运行过程中,根据条件执行不同的操作。在 VFP中,有两种实现分支结构的语句: 1.IF… else… endif 语句 2.Do Case…endcase 语句
1.IF… else… endif 语句
( IF 前的语句)
Lexp
语句组 1
语句组 2
( ENDIF 后的语句)
F
T
语法格式:
IF lExpression
Commands1
[ELSE
Commands2]
ENDIF
例 5.3 下列程序的功能是根据变量 x 的值决定变量 y 的值(为 1或 -1 )
X=8 X>0 Y=1ELSE Y=-1ENDIF?Y
( IF 前的语句)
Lexp
语句组 1
语句组 2
( ENDIF 后的语句)
F
T
IF
例 5.3 下列程序的功能是根据变量 x 的值决定变量 y 的值(为 1或 -1 )
X=-8 X>0 Y=1ELSE Y=-1ENDIF?Y
( IF 前的语句)
Lexp
语句组 1
语句组 2
( ENDIF 后的语句)
F
T
IF
例 5.4 下面方程的功能是解一元二次方程。其中,PARAMETERS语句用于接收程序的参数(三个参数a、 b、 c分别对应一元二次方程的系数)。如程序名为 cx.prg
述程序在运行时,必须使用具有 WITH子句的 DO 命令, WITH子句中给出与 a,b,c 参数对应的值。
格式: DO 程序名 WITH 1, 2, 1
一元二次方程: ax2+bx+c=0求解过程:(1) 判断 a?=0 i) 为 0 ,提示“二项式系数不能为零”,结束 ii) 不为 0 ,进入步骤( 2 )(2) 求 Δ (程序中记做 delta )的值, delta=b2-4*a*c 。 i) 判断 delta?>=0 ,是进入 i1), 否进入 i2) i1) 是 判断 i11)delta>0 ,则 x1=(-b+sqrt(delta))/(2*a),
x2=(-b-sqrt(delta))/(2*a),
结果输出,结束。 i12) delta=0 x1=x2=-b/(2*a),
结果输出,结束。 i2) 否 实部: real_part=-b/(2*a), 虚部: img_part=sqrt(-delta)/(2*a), 结果输出,结束。(3) 结束
Parameter a,b,c
Delta>=0? i2
结束
F
T
Delta>0
T
Fi12
i11
a=0?
delta=b*b-4*a*c
T
F
i1
• PARAMETERS a,b,c• IF a=0• =messagebox(" 二次项目系数不能为零! ",48," 错误显示对话框 ")• return• endif• delta=b*b-4*a*c• if delta>0• ?" 方程有两个不等的实数根: "• ??(-b+sqrt(delta))/(2*a)• ??(-b-sqrt(delta))/(2*a)• else• if delta=0• ?" 方程有两个相等的实数根: "• ??(-b)/(2*a)• else• ?" 方程有两个复根: "• real_part=-b/(2*a)• img_part=sqrt(-delta)/(2*a)• ?ALLTRIM(STR(real_part)+"+"+alltrim(str(img_part))+"i")• ?ALLTRIM(STR(real_part)+"-"+alltrim(str(img_part))+"i")• endif• endif
2.DO CASE… ENDCASE 语句 IF 语句只能判断最多两种情况,即“二分支”。若
要判断多于两种可能的情况,有两种方法可以实现。: 一是在 IF 语句中嵌套 IF 语句,这种方法虽然可行,但当情况较多时结构不是很清晰。
第二种方法就是使用DO CASE…ENDCASE 语句(简称 DO CASE 语句)。
语法格式:DO CASE CASE lExpression1 Commands1 [CASE lExpression2 Commands2 … CASE lExpressionN CommandsN] [OTHERWISE Commands]ENDCASE
DO CASE
Lexp1
Lexp2
Lexpn
其他语句组
语句组 1
语句组 n
语句组 2
ENDIF 后面的语句
……
一元二次方程: ax2+bx+c=0求解过程:(1) 判断, a?=0 i) 为 0 ,提示“二项式系数不能为零”,
结束 ii) 不为 0 ,进入步骤( 2 )(2) 求 Δ (程序中记做 delta )的值, delta=b2-4*a*c 。 i)delta=0, 则 x1=x2=-b/(2*a), 结果输出,结束。 ii)delta>0 ,则 x1=(-b+sqrt(delta))/(2*a),
x2=(-b-sqrt(delta))/(2*a), 结果输出,结束。 iii) delta<0, 则 实部: real_part=-b/(2*a), 虚部: img_part=sqrt(-delta)/(2*a), 结果输出,结束。(3) 结束
DO CASE
Delta=0
delta>0
delta<0
步骤 i
步骤 iii
步骤 ii
结束
Parameter a,b,c
a=0?T
F
delta=b*b-4*a*c
PARAMETERS a,b,cIF a=0 =messagebox(" 二次项目系数不能为零! ",48," 错误显示对话框 ")
returnendif delta=b*b-4*a*cDo case Case delta>0
?" 方程有两个不等的实数根: "??(-b+sqrt(delta))/(2*a)??(-b-sqrt(delta))/(2*a)
Case delta=0?" 方程有两个相等的实数根: "??(-b)/(2*a)
Case delta<0?" 方程有两个复根: "real_part=-b/(2*a)img_part=sqrt(-delta)/(2*a)
?ALLTRIM(STR(real_part)+"+"+alltrim(str(img_part))+"i") ?ALLTRIM(STR(real_part)+"-"+alltrim(str(img_part))+"i")endcase
5.2.4 循环结构 在应用程序中经常会遇
到重复性操、作,重复的次数有时可知、有时不可知(只能根据操作的结果确定操作是否应该结束)。为适应这样的要求,程序设计语句提供了循环语句。这类语句的执行流程如图所示。
循环入口
Lexp
语句组
循环体后的语句
.T
.
.F
.
5.2.4 循环结构 循环就是使得一组语句重复执行若干次,可以预先制定要循环的次数,也可以根据某个条件控制循环。在 Visual FoxPro 中,实现循环结构的语句有三种: FOR…ENDFOR DO WHILE…ENDDO SCAN…ENDSCAN 其中,循环开始的语句称为循环的入口语句,如:FOR 、 DO WHILE 、 SCAN ,循环结束的语句称为循环的出口语句,如 ENDFOR 、 ENDDO 、 ENDSCAN 。在入口
语句和出口语句之间的一组语句常称为循环体。
1.FOR…ENDFOR 循环结构 若预先知道循环的次数,可以使用 FOR 语 句实现
循环。FOR 语句的语法格式为:FOR nVar=nIitialValue TO nFinalValue[STEP nIncrement]CommandsENDFOR|NEXT
循环变量 nVar是作为计数器使用的变量
计数器的初始值
计数器的终值计数器增加或减少的步长,缺省时为 1
在循环体 Commands中,可以包含 LOOP和 EXIT语句。 LOOP用于将控制直接返回给 FOR语句,即忽略此后的循环体语句,以进入新的一次循环; EXIT语句将控制传递给 ENDFOR 后的第一条语句,即“跳出”循环
1.FOR…ENDFOR 循环结构FOR循环的执行过程如下:(a) 将初值赋给循环变量(b) 判断循环变量的值是否超过终值,若超过终值,则结束循环,否则执行循环体。
(c)计算循环变量的值:循环变量 =循环变量 +步长;(d)转到( b)步骤执行。
FOR nVar=nIitialValue TO nFinalValue[STEP nIncrement]
例 5.6 :下列程序的功能是计算 100 以内的奇数之和( S=1+3+5+…+99 ) , 以及 100 的阶乘( P=1*2*3*…*100 )
N=100*** 以下循环计算 n 以内的奇数和S=0for i=1 to 99 step 2S=S+iEndfor?ALLT(STR(n))+” 以内的奇数和 S=”,
S
** 以下循环计算 n 的阶乘P=1for i=1 to 100p=p*iEndfor? ?ALLT(STR(n))+” 以内的阶乘 p=”,p
FOR循环的执行过程如下:(a) 将初值赋给循环变量(b) 判断循环变量的值是否超过终值,若超过终值,则结束循环,否则执行循环体。
(c)计算循环变量的值:循环变量 =循环变量 +步长;
(d)转到( b)步骤执行。
例 5.7 下列程序的功能是求 1-100 之间的所有奇数(且这些奇数不能被 3 整除)之和。
S=0For i=1 to 100 step 2If mod(i,3)=0LoopEndifS=s+I?s
1 , 3 , 5 , 7 , 9 ,
11 , 13 , 15 , 17 , 19 ,
21 , 23 , 25 , 27 , 29 ,
31 , 33 , 35 , 37 , 39 ,
41 , 43 , 45 , 47 , 49 ,
…
例 5.8 下列程序的功能是显示如图 5-5 所示的文字。
c='金字大宝塔 'n=50for i=1 to 5
?space(50-i)for j=1 to i??substr(c,2*i-1,
2)inkey(0.5)endfor
endfor
金
字字
大大大
宝宝宝宝
塔塔塔塔塔
第 50 , 51列
49 列 52 列
例 5.9 下列程序的功能是将由英文字母组成的字符串加密。加密的算法是,如果是大写字母,用原字母后面第 4个字母代替原字母,否则用原字母后面第 2 个字母代替原字母。例如 , 明文“ China” 的密文是“ Gjkpc” 。cc=space(0)c='China'n=len(c)For i=1 to na=substr(c,i,1)nc=asc(a)If nc>96nc=nc+2Else nc=nc+4Endifcc=cc+chr(nc)Endfor?cc
A B C D E F G H I J K L M N O P Q
a b c d e f g h i j k l m n o p q
2.DO WHILE…ENDDO 循环结构
DO WHILE lExpression CommandsENDDO 其中 lExpression 用于确定是否执行 DO WHILE 和ENDDO 之间的语句组 Commands 。 若条件表达式的值为 .T., 则语句组将持续被执行。 同样,语句组 Commands 中可以包含 LOOP 语句和 EXIT
语句。
例 5.10 下列程序的功能是将由 ASCII 码字符组成的字符串进行反序显示。
clearStore 'student' to ccc=space(0)Do while len(c)>0cc=left(c,1)+ccc=substr(c,2)enddo?cc
循环入口
Lexp
语句组
循环体后的语句
.T.
.F.
例 5.10 下列程序的功能是将由 ASCII 码字符组成的字符串进行反序显示。
clearStore 'student' to ccc=space(0)Do while len(c)>0cc=left(c,1)+ccc=substr(c,2)enddo?cc
字符串 student,
反序后为: tneduts cc c len(c)
初值 ‘’ student 7
循环一次 s tudent 6
循环两次 t udent 5
循环两次 u dent 4
循环两次 d ent 3
循环两次 e nt 2
循环两次 n t 1
循环两次 t ‘’ 0
例 5.11 下列程序的功能是将由任意字符(包括汉字)组成的字符串进行反序显示。C='我是一名 student.'Cc=space(0)m=len(c)do while m>0n=asc(left(c,1))if n>127 && 不属于 asc字符集i=2 &&占两个字符的位置else i=1 &&占一个字符的位置endifcc=left(c,i)+cc && 如果是 asc字符,输出最左边的一个,否则输出两个c=substr(c,i+1) &&把输出后的字符去掉,得到新串,如“你好吗”输出
&&“你”后,剩下“好吗”m=len(c)enddo?cc
我是一名 student.
例 5.12 下列程序的功能是统计字符串中大、小写字母的个数。CLEARC='Visual FoxPro'n=0m=0Do while ‘’<>C && 作用和 len ( c ) =0 相同cc=left(c,1)c=substr(c,2)DO CASECASE asc(cc)>96 and asc(cc)<123 &&小写字母的 ASC 码n=n+1case asc(cc)>64 and asc(cc)<91 && 大写字母的 ASC 码m=m+1ENDCASEenddo?' 大写字母个数为: ',m?'小写字母个数为: ',n
例 5.13 下列程序的功能是对表达式 1/(1*2*3)+1/(2*3*4)+…+1/(n*(n+1)*(n+2)) 进行求和,并且要求计算精度小于 0.0000001
Clears=0i=1do while .t. && 循环条件始终为真n= 1/(i*(i+1)*(i+2))If n<0.0000007Exit &&退出循环体Endifs=s+ni=i+1Enddo?s
如果出现死循环,按 ESC 键退出
3.SCAN…ENDSCAN 循环结构仅用于处理表的记录。格式:SCAN[Scope][FOR lExpression][Commands]ENDSCAN例 5.14 下列程序的功能是显示所有籍贯为“江苏”的学生、姓名和籍贯。CLEARUSE xsSCAN FOR '江苏 '$jg?xm,jgendscan
5.2.5 过程与用户自定义函数 用户可以将经常执行的具有某种功能的一段代码独
立 出来,将其作为一个过程( Procedure )或用户自定义函数( User Defined Function,UDF ) , 在需要该功能
的时候调用这个过程或函数。过程通常用于实现某一处理功能,而函数用于实现某一处理功能且有返回值。但在 VFP 中,过程与用户自定义函数除了定义方式上的差别,在可以实现的功能和调用方法上没有区别。
1. 过程与自定义函数的定义过程定义的基本语法格式:PROCEDURE ProcedureName[PARAMETERS ParameterList]Commands[RETURN[eExpression]]ENDPROC
1. 过程与自定义函数的定义函数定义的基本语法格式:FUNCTION ProcedureName[PARAMETERS ParameterList]Commands[RETURN[eExpression]]ENDFUNC
最多 27个,各参数之间应用逗号分隔。
默认为 .t.
例 5.15 下列自定义函数 ntoc() 的功能是将一个 0-9 之间的阿拉伯数字转换为一个零 -九之间的中文字符。例如, ntoc(7) 的返回值为“七”。
Function ntocParamater pDigitLOCAL cStringcString=‘零一二三四五六七八九’RETURN SUBSTR(cString,pDigit*2+1,2)ENDFUNC
用户创建的过程(或自定义函数):
可以存储在数据库的存储过程中 以一个程序文件保存(一个程序文件可保存一个或多
个过程 / 自定义函数) 位于一个程序的最后。 如果过程 / 自定义函数存在于单独的文件中,则该程序文件
称为过程文件。
2. 过程与自定义函数的调用 使用 DO 命令格式:DO ProcedureName[IN ProgramName][WITH ParameterList]说明:用 DO 函数调用,无返回值,其中 IN 子句用于指定过程或自定
义函数所在的过程文件, WITH 子句用于指定传递给过程或自定义函数的参数。
使用函数的调用方式(同系统函数)
例 5.16 下列程序可用于计算 S=1!+2!+3!+4!+5!
S=0For i=1 to 5S=s+fjc(i)?fjc(i)Endfor?s
Function fjcParameter xP=1For n=1 to xp=p*nEndforReturn pendfunc
i x p fjc(i) s
1 1 1 1 1
2 2 2 2 3
3 3 6 6 9
4 4 24 24 33
5 5 120 120 153
调用
返回
S=0For i=1 to 5S=s+fjc(i)?fjc(i)Endfor?s
Function fjcParameter xP=1For n=1 to xp=p*nEndforReturn pendfunc
i x n p Fjc(i) S(初值为 0)1 1 1 p=p*n=1*1=1 1 s=s+fjc(i)
=0+1 =1
2 21 p=p*n=1*1=1
2s=s+fjc(i) =1+2 =3
2 p=p*n=1*2=2
3 3 1 p=p*n=1*1=1
6
s=s+fjc(i) =3+6 =9
2 p=p*n=1*2=2
3 p=p*n=2*3=6
4 4 1 p=p*n=1*1=1
24
s=s+fjc(i) =9+24 =33
2 p=p*n=1*2=2
3 p=p*n=2*3=6
4 p=p*n=6*4=24
5 5 1 p=p*n=1*1=1
120
s=s+fjc(i) =33+120 =153
2 p=p*n=1*2=2
3 p=p*n=2*3=6
4 p=p*n=6*4=24
5 p=p*n=24*5=120