VB程序设计 第六章 过程.docx
《VB程序设计 第六章 过程.docx》由会员分享,可在线阅读,更多相关《VB程序设计 第六章 过程.docx(45页珍藏版)》请在冰豆网上搜索。
![VB程序设计 第六章 过程.docx](https://file1.bdocx.com/fileroot1/2023-1/21/d89cca42-c46e-4093-9200-2573f327ec5c/d89cca42-c46e-4093-9200-2573f327ec5c1.gif)
VB程序设计第六章过程
第六章过程
主要内容
●函数过程的定义与调用
1.
●子过程的定义与调用
●参数传递
●变量、过程的作用域
●递归
●常用算法(三)
2.
●重点和难点
6.1函数过程的定义与调用
除了系统提供的内部函数、过程和事件过程外,用户还可自定义过程。
在VB6.0中由用户定义(称自定义)的过程可分为以下几种:
● 以“Sub”保留字开始的称为子过程;
● 以“Function”保留字开始的称为函数过程
● 以“Property”保留字开始的称为属性过程;
● 以“Event”保留字开始的称为事件过程。
1.引例
[例6.1]已知多边形的各条边的长度,要计算多边形的面积。
计算多边形面积,可将多边形分解成若干个三角形。
计算三角形面积的公式如下:
其中:
x,y,z为三条边,c为三边和的一半。
求三角形面积就可以编写一个函数过程,以后不论是求是么三角形,只要给出三边,就可象使用内部函数一样,使用这个自定义的求三角形面积的函数了。
[例6.1]在myvb\vb6\ex6_1\lbc6_1.vbp
'定义求三角形面积的函数过程
PublicFunctionarea(x!
y!
z!
)AsSingle
Dimc!
c=1/2*(x+y+z)
area=Sqr(c*(c-x)*(c-y)*(c-z))
EndFunction
PrivateSubform_click()
Dima!
b!
c!
s!
Do
Do
a=val(InputBox(prompt:
="输入一个边",Title:
="输入第一条边长",xpos:
=2000,_
ypos:
=4000,Default:
=3))
LoopUntila>0'预防按取消按钮和按转换后小于等于0的字符串
Do
b=val(InputBox(prompt:
="输入一个边",Title:
="输入第二条边长",xpos:
=2000,_
ypos:
=4000,Default:
=4))
LoopUntilVal(b)>0‘对数值变量用val函数系统也不报错
Do
c=val(InputBox(prompt:
="输入一个边",Title:
="输入第三条边长",xpos:
=2000,_
ypos:
=4000,Default:
=5))
LoopUntilVal(c)>0
LoopUntila+b>cAnda+c>bAndb+c>a
s=area(a,b,c)
Cls
Print"第一条边长=";a:
Print"第二条边长=";b:
Print"第三条边长=";c
Print"面积=";s
EndSub
PrivateSubForm_Load()
Form2.Caption="请单击窗体"
EndSub
2.函数过程的定义
自定义函数过程有两种方法:
(1)用“工具”菜单下的“添加过程”命令定义,生成一个函数的框架。
操作如下:
① 在窗体或模块的代码窗口选择“工具”菜单下的“添加过程”命令,显示“添加过程”对话框;
② 在“名称”框中输入函数过程名(过程名中不允许有空格);在“类型”选项组中选取“函数”定义函数过程;在“范围”选项组中选取“公有的”定义一个公共级全局过程;选取“私有的”定义一个标准模块级/窗体级的局部过程。
③ 然后在过程模板中,就可以编写程序代码了。
(2)利用代码窗口直接定义
在窗体或标准模块的代码窗口把插入点放在所有过程之外,直接输入函数过程名。
函数过程形式:
[Static][Public][Private]Function函数过程名([参数列表])[As类型]
局部变量或常数定义
语句块
函数名=返回值函数过程体
[ExitFunction]
语句块
函数名=返回值
EndFunction
其中:
⑴ 函数过程名的命名规则与变量名命名规则相同,但不要与VB中的关键字相同,也不要与WindowsAPI函数重名,还不能与同一级别的变量名重名。
⑵ AS类型:
表示函数返回值的类型,若缺省,则返回变体类型值。
⑶
参数列表形式:
[ByVal]变量名[()][As类型][,[ByVal]变量名[()][As类型]…]
参数也称为形参或哑元,只能是变量或数组名(数组名后则要加“()”),在定义时仅表示参数的个数、类型,但无值。
ByVal表示该过程被调用时,参数是按值传递的,否则是按引用(地址)传递的。
函数过程无参数时,函数过程名后的括号不能省略。
⑷ 函数名=返回值在函数体内至少对函数名赋值一次。
⑸ [ExitFunction]:
表示退出函数过程(EndFunction的后继语句)。
⑹ Static表示为静态的,Public表示为全局的,Private表示为局部的。
例6.2]
要求定义MyReplace(S,OldS,NewS)函数过程,其作用同标准函数Replace一样。
当调用MyReplace("abcdefgabcdecd","cd","3")时函数的返回值为"ab3efgab3e3"。
[例6.2]在myvb\vb6\ex6_2\lbc6_2.vbp
'OptionCompareText比较不区分大小写字母,默认区分。
本函数也受其影响
PublicFunctionMyReplace(s$,OldS$,NewS$)AsString
Dimi%,lenOldS%
lenOldS=Len(OldS)'取OldS字符子串长度
i=InStr(s,OldS)'在字符串中找有否OldS字符子串
DoWhilei>0'找到用NewS字符子串替换OldS字符子串
s=Left(s,i-1)+NewS+Mid(s,i+lenOldS)
i=InStr(s,OldS)'找下一个OldS字符子串
Loop
MyReplace=s'替换后的字符串赋值给函数过程名
EndFunction
PrivateSubForm_Click()
DimOriginal$,Part$,Chang$
Cls
Original=InputBox(prompt:
="输入原字符串",Default:
="abcdefgabcdecd",xpos:
=2000,ypos:
=4000,_
Title:
="第一个参数值")
Part=InputBox(prompt:
="输入被替换字符串",Default:
="cd",xpos:
=2000,ypos:
=4000,_
Title:
="第二个参数值")
Chang=InputBox(prompt:
="输入替换字符串",Default:
=3,xpos:
=2000,ypos:
=4000,_
Title:
="第三个参数值")
'说明:
调用了函数就使得参数的原来值发生了改变,因此必须注意保存才能正确显示。
'当然用下面的方法不存在这个问题。
Print"第一个参数值=";Original
Print"第二个参数值=";Part
Print"第三个参数值=";Chang
Print"替换结果值=";MyReplace(Original,Part,Chang)
EndSub
测试数据:
假定S为“abcdefgabcdecd”,Oolds为“cd”,News为"3"
(“abcdefgabcdecd”,“cd”,“3”)第1次I=3结果“ab3efgabcdecd”(“ab3efgabcdecd”,“cd”,“3”)第2次I=9结果“ab3efgab3ecd”(“ab3efgab3ecd”,“cd”,“3”)第3次I=11结果"ab3efgab3e3"
3.函数过程的调用
函数过程的调用同标准函数调用,参与表达式运算,形式如下:
函数过程名([参数列表])
注意四点:
① 参数列表,称为实参或实元,它必须与形参个数相同,位置与类型一一对应。
可以是同类型的常量、变量、表达式,数组元素。
② 调用时把实参的值传递给形参称为参数传递。
其中值传递(形参前有ByVal说明)时实参的值不能随形参值的变化而变化,而引用传递(地址传递)的实参的值随形参值一起改变。
③ 当参数是数组时,形参与实参在参数声明时应省略其维数,但括号不能省。
④ 函数过程不能作为单独的语句加以调用,必须参与表达式运算。
下面的程序段时对函数MyReplace的调用:
PrivateSubCommand1_Click()
Text1=MyReplace(Text1,"cd","3")
ST=“VisualBasic程序设计教程5.0版”
PrintMyReplace(ST,"5.0","6.0")
EndSub
执行流程示意:
Text1=MyReplace(Text1,”cd”,”3”)
PublicFunctionMyReplaec(S$,OldS$,NewS$)AsString
6.2
子过程的定义与调用
(1)不是为了获得某个函数值,而是为了某种功能的处理。
(2)要获得多个结果。
为此VB提供了功能强大的而灵活的子过程。
1.引例
[例6.3]编写一个两个数交换的过程,供多次调用。
Swap(x,y)子过程的定义
主调程序调用Swap子过程
PublicSubSwap(x,y)
'未定义参数类型,系统默认为变体,因此,对于任何不同类型的两个数据都可以实现交换
Dimt
t=x
x=y
y=t
EndSub
PrivateSubForm_Click()
'未定义参数类型,系统默认为变体。
Dima,b
a=10:
b=20
CallSwap(a,b)
Print"a=";a,",b=";b
EndSub
[例6.3]在myvb\vb6\ex6_3\lbc6_3.vbp(程序有改动)
2.子过程的定义
[Static][Public][Private]Sub子过程名[(参数列表)]
局部变量或常数定义
语句
[ExitSub]过程体
语句
EndSub
注意五点:
①ExitSub表示退出子过程,返回到调用程序的调用处。
②把某功能定义为函数过程还是子过程,没有严格规定,但只要能用函数过程定义的,肯定能用子过程定义,反之不一定。
当过程有几个值返回时,习惯上用子过程。
③函数过程名有类型,在函数体内至少有一次对函数过程名赋值。
子过程名没有值,过程名没有类型,在子过程体内不能对子过程名赋值。
④形参是过程与调用程序之间交互的接口,从调用程序获得初值,或将计算结果返回给调用程序。
⑤形参没有具体值,只代表了参数的个数、位置、类型;因此形参只能是变量,不能是常量、数组元素、表达式。
3.子过程的调用
子过程名[参数列表]
或
Call子过程名[(参数列表)](注:
有参数列表必须可加上圆括号;无,加上也强行删去)
[例6.4]分别编一计算某级数部分和的子过程和函数过程,并调用。
级数为:
用函数过程实现求部分级数的和
用子过程实现求部分级数的和
PrivateFunctionjishu1(x!
eps#)AsDouble
'使用AsDouble和AsSingle结果有细微差别
Dimt#,n%
t=1:
n=1:
jishu1=0
't每项的值,n项序
DoWhileAbs(t)>eps
jishu1=jishu1+t:
t=t*x/n
n=n+1
Loop
EndFunction
PrivateSubjishu2(s#,x!
eps#)
Dimt#,n%
t=1:
n=1:
s=0
't每项的值,s各项总和,n项序
DoWhileAbs(t)>eps
s=s+t
t=t*x/n
n=n+1
Loop
EndSub
[例6.4]在myvb\vb6\ex6_4\lbc6_4.vbp
PrivateSubCommand1_Click()
Dimf1#,f2#
f1=jishu1(2#,0.000001)'调用函数过程,x的值为2,注意第一参数的类型匹配可以
jishu2f2,2#,0.000001'调用子过程,求和解果放在实参f中
Cls
Print:
Print
Print"调用函数求和结果=";f1
Print
Print"调用子过程求和结果=";f2
EndSub
PrivateSubForm_Load()
Form2.Caption="函数过程与子过程"
EndSub
6.3参数传递
参数传递研究的是主调过程的实参与被调过程形参之间是如何传递的。
6.3.1传址与传值
传址:
在形参与实参结合时,形参得到的是实参的地址,在形参值改变的同时也就改变了实参的值。
也就是说同一地址,在主调和被调程序之间使用了不同的名字。
因此,在传址方式下的实参只可以是变量而不能是常量,表达式。
在定义过程时在形参变量前加上关键字ByRef则表示该参数是传址的(不加则系统默认为ByRef,即系统默认是传址的)。
传值:
形参得到的是实参的值,形参值的改变却不能改变实参的值。
因此,这样的实参可以是变量,常量,表达式。
在定义过程时在形参变量前加上关键字ByVal。
[例6.5]两个变量的交换(使用传址和传址的演示)
C:
\LocalFiles\_25B0_25EC_25B9_25AB\_25BE_25AB_25C6_25B7_25BF_25CE_25B3_25CC\_25D6_25D0_25D0_25C4_25C6_25C0_25BD_25A8\myvb\_25B5_25E7_25D7_25D3_25BD_25CC_25B2_25C4\ex6_5\lbc6_5.vbp
[例6.3]在myvb\vb6\ex6_5\lbc6_5.vbp
SubSwap1(ByValx%,ByValy%)‘传值
t%=x:
x=y:
y=t
EndSub
SubSwap2(x%,y%)‘传址
t%=x:
x=y:
y=t
EndSub
PrivateSubCommand1_Click()
Cls
a%=10.3:
b%=20:
‘在没有强制声明约定下,a%=10.3就是声明变量a是整型变量了,以后也不再能声明a为其他类型。
Print"ByValbefore...";"A1=";a,"B1=";b
Swap1a,b'传值实参值并没有交换
Print"ByValafter...";"A1=";a,"B1=";b
Print;"----------------------------------"
a=10:
b=20
Print"ByRefbefore...";"A1=";a,"B1=";b
Swap2a,b'传地址实参值发生了交换
Print"ByRefbefore...";"A1=";a,"B1=";b
EndSub
[例6.6]求若干个数的最大公约数。
求若干个数的最大公约数的方法是:
先求两个数的最大公约数,然后将这个最大公约数和第三个数再求最大公约数,如此下去。
在求公约数的过程中,只要有一个最大公约数为1,就不要再往下求了。
[例6.6]在myvb\vb6\ex6_6\lbc6_6.vbp
PrivateSubCommand1_Click()
DimA()AsInteger,n%,m1%,m2%,mn%,i%
Do'保证输入的串是一个大于等于2数字串
n=Val(InputBox(prompt:
="求几个数的最大公约数?
",Title:
="输入",_
Default:
=4,xpos:
=2000,ypos:
=4000))
LoopUntilVal(n)>=2
ReDimA(1Ton)'重新定义数组
Fori=1Ton
Do'保证输入的串是一个大于0的数字串
A(i)=InputBox(prompt:
="输入第"&i&"个数",Title:
="5796,5670,945,273",_
Default:
=5796,xpos:
=2000,ypos:
=4000)
LoopUntilVal(A(i))>0
Nexti
m1=A
(1)'求m1和m2的最大公约数
Fori=2Ton
m2=A(i)
mn=gcd(m1,m2)
Ifmn=1ThenExitForElsem1=mn'公约数为1停止计算
Nexti
Cls
Fori=1Ton
PrintA(i);Spc
(2);
Nexti
Print
Print"它们的最大公约数为:
";mn
EndSub
'求最大公约数值传递
PublicFunctiongcd(ByValm,ByValn)AsInteger
DimrAsInteger
Ifmm=n:
n=r
r=mModn
DoWhiler<>0
m=n:
n=r
r=mModn
Loop
gcd=n
EndFunction
6.3.2数组参数的传递
当参数是数组时只能通过传址方式进行传递。
注意以下几点:
●在实参和形参中只能写数组名,忽略维数的定义,但一对圆括号在虚参中不能省略,而对于实参可写或不写圆括号。
●在被调过程中可通过Lbound和Ubound函数确定实参数组的下、上界。
Lbound和Ubound函数的形式如:
{L|U}bound(数组名[,维数])
其中:
维数指明要测试的是第几维的下标值,缺省是一维数组。
例如:
Dima(1To5,7To25)则下式可用LBound(a,1),UBound(a,1)求出a的一维下界和上界;而用LBound(a,2),UBound(a,2)求出a的二维的下界和上界。
[例6.7]求和的值。
编一函数tim,求任意一维数组中各元素之积。
[例6.7]在myvb\vb6\ex6_7\lbc6_7.vbp
C:
\LocalFiles\_25B0_25EC_25B9_25AB\_25BE_25AB_25C6_25B7_25BF_25CE_25B3_25CC\_25D6_25D0_25D0_25C4_25C6_25C0_25BD_25A8\myvb\_25B5_25E7_25D7_25D3_25BD_25CC_25B2_25C4\ex6_7\lbc6_7.vbp
C:
\LocalFiles\_25B0_25EC_25B9_25AB\_25BE_25AB_25C6_25B7_25BF_25CE_25B3_25CC\_25D6_25D0_25D0_25C4_25C6_25C0_25BD_25A8\myvb\_25B5_25E7_25D7_25D3_25BD_25CC_25B2_25C4\ex6_7\lbc6_7.vbpPrivateSubCommand1_Click()
Dima%(1To5),b%(3To8),i%,t1#,t2#
CallInput1(a())'给A数组赋值
CallInput1(b)'给B数组赋值
t1#=tim(a)'求A数组的积
t2#=tim(b())'求B数组的积
Cls
Print"数组A各元素的值"
Fori=1To5
Printa(i);Spc
(1);
Nexti
Print
Print"数组A的积=";t1
Print
Print"数组B各元素的值"
Fori=3To8
Printb(i);Spc
(1);
Nexti
Print
Print"数组B的积=";t2
EndSub
PrivateSubForm_Load()
Form2.Caption="数组参数的传递"
Command1.Caption="计算"
EndSub
PublicSubInput1(d()AsInteger)‘输入各个数组的值,Input是关键字
Dimi%
Randomize
Fori=lbound(d)Toubound(d)
d(i)=Int(Rnd*10)
Nexti
EndSub
PublicFunctiontim(e()AsInteger)AsDouble‘求各个数组的积
Dimt#,i%
t=1
Fori=LBound(e)ToUBound(e)
t=t*e(i)
Nexti
tim=t
EndFunction
使用过程注意事项:
1.确定自定义的过程是子过程还是函数过程
函数过程名有值有类型,子过程名无值无类型。
2.过程中形参的个数和传递方式的确定
过程中参数的作用是实现过程与调用者的数据通信。
(1)从主调程序获得初值,值传递。
(2)将结果返回给主调程序,地址传递。
3.实参与形参结合时对应问题
●个数、类型、位置、次序一一对应。
●形参是值传递时,对应实参可以是表达式、常量、数组元素。
●形参是地址传递时,对应实参只能是简单变量,否则,形参不能将其值传回到到调用程序中。
●数组、记录类型、对象只能是地址传递。
6.4
变量、过程的作用域
变量、过程随所处的位置不同,可被访问的范围也不同。
变量、过程可被访问的范围称为变量、过程的作用域。
6.4.1过程的作用域
过程的作用域可分为:
窗体/模块级和全局级
1.窗体/模块级
在定义的子过程或函数过程前加Private关键