570 likes | 683 Views
第 7 章 过程. 本章学习内容 :. Sub 过程与 Function 函数定义与调用 实参与形参传递 * 值传递 * 地址传递 变量的作用域和生存周期. 本章难点 :. 1. 过程调用中数据的传递 2. 变量的作用域. 7.1 概述. Sub 与 Function 理解. VB 系统中的过程与函数 :. 就是我们今天要学习的 Sub 与 Function. 内部函数 事件过程 通用过程,即用户自定义过程与函数. 如 sqr(9)=3. 如 form_click(). 各自的执行方式:.
E N D
第7章 过程 本章学习内容: • Sub过程与Function函数定义与调用 • 实参与形参传递 • * 值传递 • * 地址传递 • 变量的作用域和生存周期 本章难点: 1.过程调用中数据的传递 2.变量的作用域
7.1 概述 Sub与Function理解 VB系统中的过程与函数: 就是我们今天要学习的Sub与Function • 内部函数 • 事件过程 • 通用过程,即用户自定义过程与函数 如sqr(9)=3 如form_click() 各自的执行方式: 总结:sub过程与Function是由用户自编写的用来实现特定功能的程序代码。先创建 再调用 事件过程 内部函数 Sub与Function 驱动激发 直接调用 先编写其功能代码,再调用
先编写程序:从键盘输入m,n(m>n),求 求n!阶乘的Function函数 Private Sub Form_click() Dim m %, n %, f !, i% , j% , k% Dim fm &, fn &, fmn & fm = 1: fn = 1: fmn = 1 i = 1: j = 1: k = 1 m = Val(InputBox("m=?")) : n = Val(InputBox("n=?")) While i <= m fm = fm * i i = i + 1 Wend While j <= n fn = fn * j j = j + 1 Wend While k <= m - n fmn = fmn * k k = k + 1 Wend f = fm / (fn * fmn) Form1.Print "f="; f End Sub Private Function fact(n As Integer) As Long Dim i As Integer, t As Long i = 1: t = 1 While i <= n t = t * i i = i + 1 Wend f = t End Function Private Sub Form_click() Dim m%, n%, f& Dim fm As Long, fn As Long, fmn As Long m = Val(InputBox("m=?")) :n = Val(InputBox("n=?")) fm = fact(m) fn = fact(n) fmn = fact(m - n) f = fm / (fn * fmn) Form1.Print "f="; f End Sub 求M! 从这个程序可看出:代码中求阶乘的3段代码的功能重复的,只是数据的不同。如果把求阶乘功能模块拎出来,作为一个独立模块,就可大大减少程序代码的冗余。 3次调用,分别求得m!,n!(m-n)! 求N! 求(m-n)!
VB中共有四种用户自定义过程 • “Sub” 保留字开始的为Sub子过程 重点学习 • “Function” 保留字开始的为Function函数过程 • “Property”保留字开始的为属性过程 • “Event”保留字开始的事件过程 不作要求
7.2 Sub过程 7.2.1 自定义过程(Sub过程) 子过程的定义形式如下: [Public|Private][Static] Sub 子过程名([形参表]) <局部变量或常数定义> <语句组> [Exit Sub] <语句组> End Sub Sub过程体 说明:(1)子过程名:命名规则与变量名规则相同。子过程名不返回值,而是通过形参与实参的传递得到结果,调用时可返回多个值。
7.2.1 自定义过程(Sub过程) (2)形式参数列表:形式参数通常简称“形参”,仅表示形参的类型、个数、位置,定义时是无值的,只有在过程被调用时,虚实参结合后才获得相应的值。 (3)过程可以无形式参数,但括号不能省。 (4)参数的定义形式: [ByVal|ByRef]变量名[( )][As 类型][,…], ByVal表示当该过程被调用时,参数是按值传递的;缺省或ByRef表示当该过程被调用时,参数是按地址传递的。
7.2.1 自定义过程(Sub过程) (6) 关键字:[Public|Private][Static] Public:表示本定义的过程可以被其他窗体、模块调用 Private:表示本定义的过程只能在本窗体中被调用 Static:表示本定义过程中的局部变量都是静态变量。 (7)代码编写在代码窗口“通用区的声明”区域 或 标准模块文件(*.Bas)
7.2.2 Sub过程的调用(1) 1 sub过程的调用 (1) 格式一: 子过程名 [参数列表] (2) 格式二: Call 子过程名(参数列表) 说明: (1)参数列表称为实参或实元,它必须与形参保持个数相同,位置与类型一一对应。 (2)调用时把实参值传递给对应的形参。其中值传递(形参前有ByVal说明)时实参的值不随形参的值变化而改变。而地址传递时实参的值随形参值的改变而改变。
7.2.2 Sub过程的调用(2) (3)当参数是数组时,形参与实参在参数声明时应省略其维数,但括号不能省。 (4)调用子过程的形式有两种,用Call关键字时,实参必须加圆括号括起,反之则实参之间用“,”分隔。如: Swap a,b Call Swap(a,b)
7.2 .3 Sub过程举例 形参的数据类型 例7.1 编一个交换两个整型变量值的子过程。 Private Sub Swap( X As Integer, Y As Integer) Dim temp As Integer Temp=X : X=Y : Y=Temp End Sub 形参:接收被主程序调用时实参传来的值或地址 Private Sub command1_click() Dim a%,b% a=val(inputbox(“a=“)) b=val(inputbox(“b=“)) print “a=“;a,”b=“,b call swap(a,b) print “a=“;a,”b=“,b End Sub 实参:有具体的值,可以是常量、变量、表达式、数组 实参与形参一一对应,包括个数、数据类型、位置
7.2.4 Sub过程调用的执行过程: Sub子过程 主程序 Private Sub Swap(x%,y%) Dim temp% Temp=X X=Y Y=Temp End Sub Sub command1_click() Dim a%,b% a=val(inputbox(“a=“)) b=val(inputbox(“b=“)) print “a=“;a,”b=“,b call swap(a,b) print “a=“;a,”b=“,b End Sub 调用出口 返回入口
例:编程,将数组中各元素按值从大到小排列,要求将数组的排序编写为sub过程。例:编程,将数组中各元素按值从大到小排列,要求将数组的排序编写为sub过程。 Private sub sort(a() as single,n as byte) dim I as byte ,j as byte,k as byte,temp as single for I=1 to n-1 k=I for j=I+1 to n if a(j)>a(k) then k=j next j temp=a(k) : a(k)=a(i) : a(i)=temp Next I End sub 思考:如何调用,实现数组排序?
7.3Function过程 Visual Basic函数分为内部函数和外部函数,外部函数是用户根据需要用Function关键字定义的函数过程,与子过程不同的是函数过程将返回一个值 。
函数体 7.3.1 函数过程(Function过程)的定义 函数返回值类型 [Public|Private][Static]Function函数名([<参数列表>])[As<类型>] <局部变量或常数定义> <语句块> [函数名=返回值] [Exit Function] <语句块> [函数名=返回值] End Function 通过函数名把值返回给上一级调用程序
说明: (1)函数名:命名规则与变量名规则相同。但不能与系统的内部函数或其它通用子过程同名,也不能与已定义的全局变量和本模块中模块级变量同名。 (2)在函数体内,函数名可以当变量使用,函数的返回值就是通过对函数名的赋值语句来实现的,在函数过程中至少要对函数名赋值一次。 (3)AS类型:是指函数返回值的类型,若省略,则函数返回变体类型值(Variant)。 (4)Exit Function:表示退出函数过程,常常是与选择结构(If或Select Case语句)联用,即当满足一定条件时,退出函数过程。 (5)形参数列表:形参的定义与子过程完全相同。
7.3.2 函数的调用 调用形式如下: 函数名(实参列表) 说明: 在调用时实参和形参的数据类型、顺序、个数必须匹配。函数调用只能出现在表达式中,其功能是求得函数的返回值。
例:编制求n!的Function过程,调用过程求 3!+7! 形参 Private function fact(n as integer) as long Dim t as long,I as integer T=1 For I= 1 to n T=t*I Next I Fact=t End function 执行过程: Private sub form_click() Dim s&, s1& , s2& S1=fact(3) S2=fact(7) S=s1+s2 Print “3!+7!=”;s End sub (2) (1) (6) (3) (7) 实参 (5) (4) (8) (9)
例: 编写判断一个整数是不是素数写函数过程。如果给定的整数是素数,则返回逻辑值True,否则返回False例: 编写判断一个整数是不是素数写函数过程。如果给定的整数是素数,则返回逻辑值True,否则返回False Private Function Prime(n As Integer) As Boolean Dim k%,Yes As Boolean Yes=True For k=2 to int(sqr(n)) IF n mod k =0 then Yes=False Exit For endif Next k Prime=Yes ‘ 给函数名赋值,作为函数的返回值 End Function 思考:如何调用该函数呢?求出1~1000之内的所有素数
Sub与Function的不同之处: 1。声明的语法格式不同。Function函数需对返回值的类型进行说明,Sub不需要。 2。调用方式的不同。Function通常是通过表达式的方式来调用,而Sub是用:子程序名 参数列表 或 call子程序名( 参数列表) 3. Function可以通过函数名返回值,而Sub不能。
7.4 参数的传递 • Visual Basic中不同模块(过程)之间数据的传递有两种方式: • 通过过程调用实参与形参的结合实现; • 使用全局变量来实现各过程中共享数据。
7.4.1 形式参数与实际参数 1、形式参数 是指在定义通用过程时,出现在Sub或Function语句中的变量名后面园括号内的数,是用来接收传送给子过程的数据,形参表中的各个变量之间用逗号分隔。 2、实际参数 实际参数是指在调用Sub或Function过程时,写入子过程名或函数名后括号内的参数,其作用是将它们的数据(数值或地址)传送给Sub或Function过程与其对应的形参变量。 实参可由常量、表达式、有效的变量名、数组名(后加左、右括号,如A())组成,实参表中各参数用逗号分隔。
7.4.2 参数传递(虚实结合) 参数传递指主调过程的实参(调用时已有确定值和内存地址的参数)传递给被调过程的形参,参数的传递有两种方式:按值传递、按地址传递。形参前加“ByVal”关键字的是按值传递,缺省或加“ByRef”关键字的为按地址传递。
传址与传值 传址: 形参得到的是实参的地址,当形参值的改变同时也改变实参的值,是一种双向传递: 传值: 形参得到的是实参的值,形参值的改变不会影响实参的值,是一种单向传递: 实参 形参 实参 形参 例:读如下程序,观察程序运行结果 Private sub form_click() a=3 : b=3 Call f1(a) Call f2(b) Print “a=”;a,”b=”;b Private sub f1(byval n as integer) N=n+5 Endsub 输出: a=3 b=5 Private sub f2(byref n as integer) N=n+5 Endsub
例7.4 Sub Swap1(ByVal x%, ByVal y%) Dim Temp% Temp = x: x = y: y = Temp End Sub Sub Swap2(x%, y%) Dim Temp% Temp = x: x = y: y = Temp End Sub Private Sub CmdOK_Click() a% = 10: b% = 20 Swap1 a, b ‘传 值 Print "A1="; a, "B1="; b a = 10: b = 20 Swap2 a, b '传地址 Print "A2="; a, "B2="; b End Sub 输出:A1=10 B1=20 输出:A1=20 B1=10
值传递的执行过程如下图: 通过地址传递数据的执行过程
数据传递的几点说明: 1.参数的数据类型 2.按值传递参数 形参是实参的一个副本 3.按地址传递参数 形参实参公用内存单元 4.子过程执行一系列操作,函数过程返回一个值 注意:如果实参是常量(系统常量、符号常量)或者表达式,则无论定义时使用值传递还是地址传递,都是按值传递将常量或者表达式的计算值传递给形参。
数据传递的几点说明: 1.参数的数据类型 2.按值传递参数 形参是实参的一个副本 3.按地址传递参数 形参实参公用内存单元 4.子过程执行一系列操作,函数过程返回一个值 注意:如果实参是常量(系统常量、符号常量)或者表达式,则无论定义时使用值传递还是地址传递,都是按值传递将常量或者表达式的计算值传递给形参。
7.5 数组作过程的参数 Visual Basic允许把数组作为实参传送到过程中。数组作参数是通过传地址方式传送。在传送数组时,除遵守参数传送的一般规则外,还应注意以下几点: 1.把一个数组的全部元素传送给一个过程,应将数组名分别写入形参列表中,并略去数组的上下界,但括号不能省略。 Private Sub Sort( a() As single,n as integer) …… End Sub 其中形参“a( )”即为数组。
2.被调过程可通过Lbound和Ubound函数确定实参数组的上、下界。2.被调过程可通过Lbound和Ubound函数确定实参数组的上、下界。 3.当用数组作形参时,对应的实参必须也是数组,且类型一致。 4.实参和形参结合是按地址传递,即形参数组和实参数组共用一段内存单元。 例如:定义了实参数组b(1 to 8),给它们赋了值,调用Sort()函数过程的形式如下: Sort b() 或Call Sort(b() ) 实参数组后面的括号可以省略,但为便于阅读,建议一般不要省略为好。 调用时形参数组a和实参数组b虚实结合,共用一段内存单元,如下所示。因此在Sort()过程中改变数组a的各元素值,也就相当于改变了实参数组b中对应的元素的值,当调用结束时,形参数组a成为无定义。 b(1) b(2) b(3) b(4) b(5) b(6) b(7) b(8) a(1) a(2) a(3) a(4) a(5) a(6) a(7) a(8) 参数为数组时虚实结合示意图
例:编制一个函数,其功能是求一个二维数组中所有元素之和例:编制一个函数,其功能是求一个二维数组中所有元素之和 Private function ff(a() as single,m as byte,n as byte) as single dim I as byte, j as byte for I=1 to m for j=1 to n ff=ff+a(I,j) next j Next I Private sub form_click() dim x(2,3) as single for I=1 to 2 for j=1 to 3 a(I,j)=int(rnd*90)+10 next j next I s=ff(x,2,3) print “s=”;s End sub
例:求a数组与b数组间最小值之差 Function min(t() as integer,n as integer) as integer min=t(1) For I=2 to n if t(i)<min then min=t(i) Next I End function Private sub command1_click() dim a(10) as integer,b(7) as integer for I=1 to 10 a(i)=int(rnd*900)+10 next I For I=1 to 7 b(i)=int(rnd*90)+10 Next I Abmin=min(a,10)-min(b,7) Print abmin
7.5 过程和变量的作用域 在第二章我们介绍了VB应用程序(通常称为工程)的组织结构,它由窗体模块、标准模块和类模块组成。VB程序代码就保存在窗体模块文件(*.Frm)、标准模块文件(*.Bas)或类模块文件(*.Cls)中。它们形成了工程的一种模块层次结构,如下图所示。
7.5.1 过程和变量的作用域 概 述 在第二章我们介绍了VB应用程序(通常称为工程)的组织结构,它由窗体模块、标准模块和类模块组成。VB程序代码就保存在窗体模块文件(*.Frm)、标准模块文件(*.Bas)或类模块文件(*.Cls)中。它们形成了工程的一种模块层次结构,如下图所示。
7.5.2 窗体模块 (文件扩展名为.FRM ) 窗体模块。窗体模块可以包含处理事件的过程、通用过程以及变量、常数、类型和外部过程的窗体级声明。如果要在文本编辑器中观察窗体模块,则还会看到窗体及其控件的描述,包括它们的属性设置值。写入窗体模块的代码是该窗体所属的具体应用程序专用的;它也可以引用该应用程序内的其它窗体或对象。
7.5.3 标准模块 (文件扩展名为.BAS) 它们可以包含变量、常数、类型、外部过程和全局过程的全局(在整个应用程序范围内有效的)声明或模块级声明。写入标准模块的代码不必绑在特定的应用程序上,则在许多不同的应用程序中可以重用标准模块。
7.5.4 类模块 (文件扩展名为.CLS) 在Visual Basic 中类模块是面向对象编程的基础。可在类模块中编写代码建立新对象。这些新对象可以包含自定义的属性和方法。实际上,窗体正是这样一种类模块,在其上可安放控件,可显示窗体窗口。
7.6过程的作用域 概念 [Public|Private] Sub 子过程名([形式参数列表]) ….. End Sub 通用子过程和函数过程既可写在窗体模块中也可写在标准模块中,在定义时可选用关键字Private(局部)和Public(全局),来决定它们能被调用的范围。
按过程的作用范围来划分,过程可分为: • 模块级过程 • 全局级过程 1、窗体/模块级过程: 加 关键字的过程,只能被定义的窗体或模 块中的过程调用。 2、全局级过程: 加 关键字 的过程,可供该应用程序的所有窗体和所有标准模块中的过程调用。 Private (或缺省) Public
总结归纳过程的定义及作用域如下表(教材Pg126)总结归纳过程的定义及作用域如下表(教材Pg126)
7.7 变量的作用域 区分标准 概述: • 在VB中,由于可以在过程中和模块中声明变量,根据定义变量的位置和定义变量的语句不同,变量可以分为: • 局部变量(过程级变量) • 窗体/模块级变量(私有的模块级变量,能被本模块的所有过程和函数使用) • 全局级变量(公有的模块级变量)。
7.7.1 过程级变量——局部变量 局部变量:在过程内用声明的变量,只能在本过程中使用。 在过程内部使用 Dim 或者 Static 关键字来声明的变量,只在声明它们的过程中才能被访问或改变该变量的值,别的过程不可访问。所以可以在不同的过程中声明相同名字的局部变量而互不影响。
7.7.2 窗体/模块级变量 窗体/模块级变量:在“通用声明”段中用Dim语句或用Private语句声明的变量,可被本窗体/模块的任何过程访问。但其他模块却不能访问该变量。 例如:在“通用声明”段声明如下变量 Private s As String Dim a As Integer,b As Single
例: 局部变量 窗体级变量 代码2: Dim n% Private Sub Form_Load() n= 10 End Sub Private Sub Form_Click() Print “n=“;n End Sub 代码1: Private Sub Form_Load() Dim n% n= 10 End Sub Private Sub Form_Click() Dim n% Print “n=“;n End Sub 输出: n=10 输出 n=0 程序运行后单击窗体,其输出结果分别是什么?
7.7.3 全局变量 全局变量也称公有的模块级变量,在窗体模块或标准模块的顶部的“通用”声明段用Public关键字声明,它的作用范围是整个应用程序,即可被本应用程序的任何过程或函数访问。 例如: Public a As Integer,b As single
例: 由键盘输入10个数,输出其中的最大数和平均值,并将这10个数从小到大排序输出到窗体上。 要求:分别编写子过程Maxnum,Avenum和Sortnum来求最大数、平均值和排序,然后在窗体的单击事件过程中调用这些函数。
7.7.4 关于多个变量同名 一、公用变量与局部变量同名 在不同过程中定义同名变量,它们互不影响,但若在一过程中定义使用了与全局变量同名的变量,则就应注意。 注意:在过程中,如果定义了与模块级变量(在通用部分使用Private或Dim声明的变量),则在该过程内不能引用同名的模块级变量。例如,下面的例子中,如果将定义全局变量的语句Public Temp As Integer改为Private Temp As Integer 则在Command1的单击事件中就不使用模块级的Temp变量。
Public Temp As Integer ' 定义全局变量 Private Sub Form_Load() Temp = 1 ' 将全局变量Temp 的值设置成1 End Sub Private Sub Command1_Click() Dim Temp As Integer ' 定义局部变量 Temp = 2 ' 将局部变量Temp 的值设置成2 Print “temp=”; Temp Print "temp="; Form1.Temp End Sub Private Sub Command2_Click() Print "temp="; Temp End Sub 输出值为2 输出值为1 输出值为1