1、VB程序设计,唐四薪,6.1 子过程的定义与调用 6.2 函数的定义与调用 6.3 子过程与函数的参数传递 6.4 变量、过程的作用域 6.5 递归 6.6 常用算法举例,第6章 过程与函数,本节课要求,1 . 掌握Sub过程、Function函数的定义和调用 2. 理解Sub过程和Function函数的区别 3. 掌握编写过程和函数的一般流程,引入过程和函数的目的,1.依据结构化程序设计的思想,实现模块化的程序设计 当需解决的问题规模较大、复杂时,可以按功能细分成一个一个小的功能模块,这样的小程序段,在VB中被称为过程; 2. 简化程序中多处重复出现处理相同功能的程序段的设计问题 过程的定义
2、:过程是一段能完成一个或多个特定功能的独立的程序段,并可以被其他过程调用 特点:功能独立;可被调用,VB中的过程有两种:(1) 系统提供的内部函数过程和事件过程。(2) 用户根据应用的需要而设计的过程。在VB中根据应用的要求可分为几种类型的自定义过程:(1) 以“Sub”保留字开始的子过程。(2) 以“Function”保留字开始的函数过程。(3) 以“Property”保留字开始的属性过程。(4) 以“Event”保留字开始的事件过程。本书仅讨论以“Sub”开头的子过程和以“Function”开头的函数过程。,过程和函数,在VB中,过程有两种,一种是Sub子过程,一种是Function函数。
3、 两者的区别在于: Sub子过程只执行程序而不返回值, 而Function函数执行程序后会返回值。,函数Function和过程Sub的区别,函数 Function,参数1,参数2,返回值,过程 Sub,函数:既有输入又有输出:如数控机床、打爆米花的机器,过程:只有输入没有输出:如光驱,参数n,打爆米花,建立函数的一般过程,Function 函数名(形式参数1,形式参数2,) End Function 输入:? 输出:? Function 打爆米花(粮食,糖精) 打爆米花=爆米花 End Function,6.1.1 子过程的定义,在VB中用Sub 语句定义的过程叫做子过程。可按下列格式定义子过
4、程:Sub 子过程名 ( 形式参数列表 )语句序列End Sub,子过程的定义,Sub sub1 (a as long, b as long)c = a+bprint c End Sub 形式参数列表由若干个形式参数构成,参数之间用逗号分隔。每个形式参数按下列格式定义::形式参数名 As 类型名 省略类型说明则表示是Variant类型。 子过程中可以使用Exit Sub语句跳出子过程。,6.1.2 子过程的调用,子过程只能作为语句被调用,不能作为表达式被调用(即不能把子过程赋值给某个变量)。可以用下列两种方法调用子过程:Call 子过程名( 实际参数列表 ) 或 子过程名 实际参数列表 以上两
5、种调用方法功能完全一致。注意,当使用 Call 语法时,参数必须在括号内。 Call sub1(2,3) 或 sub1 2,3,6.1.2 通用子过程,7)End Sub标志Sub过程执行结束,程序将返回调用该Sub过程的语句处继续执行; 8)过程不能嵌套定义。 Private Sub Command1_Click()Call P() End Sub,Private Sub ()Print “输出结果为:” End Sub,事件过程,事件过程的调用:当有事件发生时,系统会自动调用与事件相对应的事件过程。事件过程是与对象相关联的,是对象对事件做出的响应。事件过程的名称由对象名、下划线、事件名连接
6、而成。,Sub过程(子程序),Sub子程序的语法如下: Sub 子程序名(形式参数1,形式参数2,) End Sub 调用子程序的两种方式: (1)Call 子程序名(实际参数1,实际参数2,) (2)子程序名 实际参数1,实际参数2,,Function函数,Function函数的语法如下: Function 函数名(形式参数1,形式参数2,) End Function 调用函数 变量= Function 函数名(参数1,参数2,) 函数可以向变量一样引用和参与运算,6.2 定义Function过程,定义Function过程说明: 1)Function过程以Function语句开头,以End
7、Function结束;中间代码部分为函数体; 2)函数名有返回值,其值类型由As 数据类型指定; 3)函数体内一般都会至少为函数名赋值一次;如果不赋值,函数返回值默认为0或空; 4)函数中途可以利用Exit Function退出。,Function函数返回值的方式,与Sub过程不同的是,Function函数通过函数名返回一个值,这个值是在过程的语句中赋给函数名的。 Function mySquare(intA,intB) intA和intB是形式参数 Dim lngSum lngSum=intA2+intB2 mySquare=lngSum End Function,函数可以作为表达式来调用。
8、格式为:函数名(实际参数列表)如果函数要直接作为语句来使用,则必须按照子过程的方式来调用,当然此时也就不能利用函数的返回值了。例如下列三条语句都可以调用前面定义的函数Fun1:Print fun1(2, 3)Call fun1(2, 3)fun1 2, 3,6.2.2 函数的调用,6.2 定义Function过程,例如,求n! Private Function fac%(n As Integer) If n0 Then fac = -1:Exit FunctionElse fac = 1For i = 1 To nfac = fac*iNext iEnd If End Function,6.2
9、 定义Function过程,例如,求m, n的最大公约数 Private Function gcd%(ByVal m%,ByVal n%) Dim r%,t%If m0m = nn = rr = m Mod nLoopgcd = n End Function,Private Sub Change(x1%, x2%)Dim Temp As IntegerTemp = x1x1 = x2x2 = Temp End Sub,过程和函数需注意的几点,过程的定义不可以嵌套 函数和过程必须先定义才能使用 使用自定义过程的两个步骤:定义过程和调用过程,函数和过程的相互转换,写函数首先要确定函数的输入和输出
10、Private Sub Command1_Click() Print sum(5, 3) End Sub Function sum(x, y) s = x + y sum = s End Function,定义函数,调用函数,函数和过程的相互转换,Private Sub Command1_Click() Call sum(5, 3, s) Print s End Sub Sub sum(x, y, s) s = x + y End Sub,定义过程,调用过程,例题,编写一个求任意三角形面积的函数,Private Function Area!(a!, b!, c!)Dim t!t = (a+b+
11、c)/2Area = Sqr(t*(t-a)*(t-b)*(t-c) End Function,例题,编写一个求任意三角形面积的子过程,Private Sub Area (a!, b!, c!, s!)Dim z!z = (a+b+c)/2s = Sqr(z*(z-a)*(z-b)*(z-c) End Sub,过程实例,定义Sub过程判断手机号码格式是否正确并调用它 Sub IsTel (tel)if len(tel)=11 and IsNumeric(tel) thenPrint “手机号码格式正确“elsePrint “格式不正确,请重新输入“end if end Sub Call IsT
12、el(“13388888888“) 调用Sub过程,函数的实例,限制标题显示的内容长度的函数 ,如果输入的字符串(tit)长度大于指定的长度(n),则返回按指定的长度截取前面部分并加省略号的字符串,如果长度小于等于指定长度,则返回原字符串。 function title(tit,n) if len(tit)n thentitle=left(tit,n)&“ 返回函数值 elsetitle=tit 返回函数值 end if end function,5.7 参数传递,5.7.1 形参与实参,形参:置于过程定义时,参数列表中的变量或数组;在过程被调用前,系统不对其分配空间; 实参:当程序中想调用某
13、过程时,所提供的实际值; 当实参和形参结合的时候,形参才被分配空间,接收由实参传递过来的值; 形参、实参个数、类型、位置要一致。,6.4.1 形参与实参,常见的错误 Private Sub F1(a%,b%) . End Sub Private Sub Command1_Click()Dim x!,y!x = 3.14:y = 123Call F1(x,y) Call F1(x) End Sub,5.7.2 参数传递方式,传值(ByVal) 传址(ByRef或省略默认)区别1:形参定义前面放的关键字不一样; 区别2:形参接收到的值不一样; 区别3:形参对实参的影响不一样,6.4.23 参数传递
14、方式,例如:(两个数的交换) Private Sub Exchange(ByVal a%, ByVal b%) Dim t% t = a a = b b = t Print a,b End Sub,Private Sub Command1_Click() Dim x%,y% x = 12 y = 21 Call Exchange(x,y) Print “主过程中:“;x,y End Sub,6.4.23 参数传递方式,说明: 形参前加ByVal时表示传值 不加或加ByRef时表示传址 传值是单方向的 传址是“双方向的”,6.4.23 参数传递方式,Private sub add(x as in
15、teger, y as integer, z as integer)z=x+yx=x+1y=y+1print “子过程中” & x & y & z End sub Private sub Form_Click()dim a as integer, b as integer, c as integera=3:b=2:c=1add a, b, c 或者写成Call add(a,b,c)print “外部过程中” & a & b & c End sub,1.参数传递方式过程的参数有两种传递方式: 传值(ByVal) 传地址(ByRef)(默认方式)。按值传递参数:在形式参数前加上关键字ByVal表示
16、指定按值传递参数。调用时实际参数仅将值传递给形式参数,形式参数的任何改变不会影响实际参数。,6.3 子过程与函数的参数传递,按地址传递参数: 在形式参数前加上关键字ByRef表示指定按地址传递参数。 调用时如果实际参数是表达式,则传递方式与按值传递效果相同;如果实际参数是变量,则将实际参数的内存地址传递给形式参数,形式参数与实际参数指向同一个内存地址,形式参数的改变也就是实际参数的改变。,6.3 子过程与函数的参数传递,【例6-4】下列程序运行后,每次单击窗体就会显示“a=3”,“b=8”。Option ExplicitDim a As LongDim b As IntegerSub s(c
17、As Long)c = c + 1End SubSub Form_Click()a = 2b = 8s aPrint “a=“; as (b) Print “b=“; b End Sub 说明:本例中,圆括号用于将实际参数由变量b转换为表达式,即按值传递(s(b),否则就是按址传递(s a)。,2.可选参数在形式参数前加上关键字Optional可以指定该形式参数为可选参数。可选参数在过程调用时可以不提供与可选参数对应的实际参数。可选参数可以指定默认的缺省值。 3.命名参数实际参数使用“形式参数名:= 实际参数”的格式即为命名参数。命名参数出现的位置可以与定义时的顺序无关。但需注意非命名参数仍需
18、按定义时的位置出现,所以非命名参数在定义时应排在第一个命名参数之前。 4.数组作为参数和返回值数组可以作为实际参数传递到过程中。此时形式参数应为Variant类型或与实际参数类型完全相同的数组类型。作为形式参数的数组应为可变数组,用数组名跟空的圆括号表示。函数的返回值也可以是数组,此时类型说明为Variant类型或“As 类型()”。,6.3 子过程与函数的参数传递,【例6-7】下列程序运行后,单击窗体时显示“9”、 “8”、“7”。Option ExplicitFunction f(a() As Long) As Long()f = aEnd FunctionSub Form_Click()
19、Dim b() As LongDim c(2) As Longc(0) = 9c(1) = 8c(2) = 7b = f(c)print b(0)b()=f(c()print b(1)Print f(c)(2) 函数表达式直接带数组下标代表数组元素End Sub,6.3 子过程与函数的参数传递,5.可变个数参数将最后一个形式参数声明为Variant类型的数组,同时在前面加上ParamArray关键字,就变成可变个数的参数;调用过程时可输入任意个数的参数,输入的参数转变为数组的元素;也可以省略该参数。ParamArray 关键字不能与 ByVal或ByRef一起使用,也不能在参数列表中出现Opt
20、ional。 【例6-8】下列程序运行后,每次单击窗体就会显示“6”。Option ExplicitFunction f(a, ParamArray b()f = a + b(0) + b(1) End FunctionSub Form_Click()Print f(1, 2, 3)End Sub注意:在用可变个数参数时,实参个数不能少于使用的形参个数。,6.3 子过程与函数的参数传递,6.4 变量、过程的作用域,1.过程的作用域定义过程时在过程名前加关键字Private,则该过程为私有过程,仅在定义该过程的模块内有效,其他模块的过程不能调用该过程。如果没有加关键字Private或加了关键字P
21、ublic,则该过程为公共过程,在整个工程内有效,其他模块内的过程可以调用该过程。调用当前过程所在模块定义的过程可以直接使用过程名。调用其他窗体模块或其他标准模块定义的过程,使用“模块名.过程名”的格式。,Private Sub Form_Click()Print “第1次调用过程b“bPrintPrint “第2次调用过程b“bPrintPrint “第1次调用静态过程e“e 0PrintPrint “第2次调用静态过程e“e 0 End Sub,6.4 变量、过程的作用域,运行结果如图所示。,过程如果直接或间接地调用了自身,这就是递归过程。 例【6-12】求n!的递归函数。 Public
22、Function FN(n As Integer) As Integer if n=1 Then FN=1 Else FN=n*FN(n-1) End if End Function 可见递归是一个不断自己调用自己的过程,6.5 递归,【例6-13】一只猴子一天从山上摘来一袋桃子,从这天开始,它每天都要把袋中的桃子平分为二堆,吃掉其中的一堆,然后再从剩下的桃中拿出一个解谗,等到第10天,它发现袋中只有一只桃可吃,问猴子总共摘了多少桃。 程序如下(运行结果如下图): Private Sub Command1_Click()Dim Num As IntegerNum = Val(InputBox(
23、“请输入天数:“)Label1.Caption = “桃子数量为:“ & Eat(Num) End Sub Private Function Eat(N As Integer) 递归函数If N = 1 ThenEat = 1ElseEat = 2 * Eat(N - 1) + 2End If End Function,6.5 递归,6.6 常用算法举例,程序设计不仅仅需要具备程序设计语言的语法知识,更重要的是要掌握基本的算法并能灵活的加以应用。下面给出一些常用算法的应用实例 。 1.欧几里德算法求最大公约数和最小公倍数欧几里德算法也叫做辗转相除法,是计算两个数最大公约数的传统算法。步骤如下:
24、 (1)如果a b,则交换a和b。 (2)令c是a / b的余数。 (3)如果c0,则令gcdb并终止;否则令ab,bc并转向步骤(2)。具体算法应用见下例:,【例6-15】求最大公约数的函数为:Function gcd(ByVal a As Long, ByVal b As Long) As LongDim c As LongIf a b Thenc = a: a = b: b = cEnd IfDoc = a Mod bIf c = 0 Then Exit Doa = b: b = cLoopgcd = b End Functiongcd函数的调用和系统函数的调用一样,如:Print gc
25、d(12,28)为输出12与28的最小分倍数。,6.6 常用算法举例,2.异或操作实现加密和解密 【例6-17】异或操作可以实现简单的数据加密和解密,加密解密使用相同的密码和程序。,6.6 常用算法举例,Function code(src() As Byte,key() As Byte) As Byte()Dim a() As ByteDim i As LongDim j As LongDim K As LongDim L As LongK = UBound(src)L = UBound(key)ReDim a(k)j = 0For i = 0 To Ka(i) = src(i) Xor ke
26、y(j)j = j + 1If j L Then j = 0Next icode = a End Function,Private Sub Form_click()Dim a() As ByteDim b() As ByteDim c() As Bytea = “用于加密的密码“b = “密码“Print “加密前的明文:“; aa = code(a, b) 将原文与密码进行异或运算,实现对原文的加密Print “加密后的密文:“, aa = code(a, b) 将密文与密码进行异或运算,实现对密文的解密Print “解密后的明文:“, a End Sub,3.数制转换 【例6-18】将任意
27、进制正整数形式的字符串转换为数值(十进制),实现函数如下:Function str2n(ByVal a As String, Optional ByVal b As Long) As LongDim i As LongDim num As LongDim c As String * 1For i = 1 To Len(a)c = mid(a, i, 1)c = UCase(c)If c = “0“ And c = “A“ And c = “Z“ Thennum = num * b + Asc(c) - Asc(“A“) + 10End IfNext istr2n = numEnd Functi
28、on,6.6 常用算法举例,4.多项式求值和求导数 【例6-19】多项式 a0 xn + a1 xn-1+ + an-1x+ an 的值可以用下面的函数计算:Function polynomial(a() As Double, ByVal x As Double) As DoubleDim i As LongDim fx As Doublefx = a(0)For i = 1 To UBound(a)fx = x * fx + a(i)Next ipolynomial = fxEnd Function,6.6 常用算法举例,本章介绍了与过程的定义与调用有关的内容。过程有两种基本的形式:子过程与函数,这两种形式没有本质的区别。子过程是事件响应过程采用的形式,函数则使用起来更为灵活。过程调用时的参数有两种传递方式:值传递和引用传递。值传递仅仅是复制实际参数的副本传递给形式参数,所以形式参数的变化不会影响实际参数的值,引用传递时形式参数与实际参数是同一个变量,形式参数的改变也就是实际参数的改变。过程和变量都有作用域限制,同名过程或变量在调用时有优先级的差异,变量还有生存期的问题。本章最后给出了一些实用的自定义过程,读者可从中学习算法,加深对语法知识的理解。,本章小结,