1 / 133

第五章 过程和函数

第五章 过程和函数. 5.1 VB 应用程序结构 5.2 子过程的定义和调用 5.3 函数过程的定义和调用 5.4 过程调用中的参数传递 5.5 过程和变量的作用域 5.6 过程的嵌套和递归 5.7 结束语句 5.8 程序调试与错误处理 5.9 巩固与提高. VB 应用程序 . VBP. 类模块 . Cls. 标准模块 . Bas. 窗体模块 . Frm. 函数过程 (Function). Sub 过程. 事件过程. Sub 过程. 函数过程 (Function). 5.1 VB 应用程序结构.

caspar
Download Presentation

第五章 过程和函数

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 第五章 过程和函数 5.1 VB应用程序结构 5.2 子过程的定义和调用 5.3 函数过程的定义和调用 5.4 过程调用中的参数传递 5.5 过程和变量的作用域 5.6 过程的嵌套和递归 5.7 结束语句 5.8 程序调试与错误处理 5.9 巩固与提高

  2. VB应用程序 .VBP 类模块 .Cls 标准模块 .Bas 窗体模块 .Frm 函数过程 (Function) Sub过程 事件过程 Sub过程 函数过程 (Function) 5.1 VB应用程序结构    在建立VB应用程序时,应先设计代码的结构。VB应用程序的结构通常如图所示。 图5-1 VB应用程序结构图

  3. VB将代码存储在3种不同的模块中:窗体模块,标准模块和类模块。在这3种模块中都可以包含常量和变量的声明以及Sub、Function过程。它们形成了工程的一种模块层次结构,可以较好地组织工程,同时也便于代码的维护。如下图所示。VB将代码存储在3种不同的模块中:窗体模块,标准模块和类模块。在这3种模块中都可以包含常量和变量的声明以及Sub、Function过程。它们形成了工程的一种模块层次结构,可以较好地组织工程,同时也便于代码的维护。如下图所示。 图5-2 工程中的模块

  4. 5.1.1 窗体模块 每个窗体对应一个窗体模块,窗体模块包含窗体及其控件的属性设置、窗体变量的说明、事件过程、窗体内的通用过程、外部过程的窗体级声明。窗体模块保存在扩展名为.frm的文件中。默认时应用程序中只有一个窗体,因此有一个以.frm为扩展名的窗体模块文件。如果应用程序有多个窗体,就会有多个.frm为扩展名的窗体模块文件。

  5. 5.1.2 标准模块    简单的应用程序通常只有一个窗体,这时所有的代码都放在该窗体模块中。而当应用程序庞大而复杂时,就需要多个窗体。在多窗体结构的应用程序中,有些程序员创建的通用过程需要在多个不同的窗体中共用,为了不在每个需要调用该通用过程地窗体重复键入代码,就需要创建标准模块,标准模块包含公共代码的过程。    标准模块保存在扩展名为.bas的文件中,缺省时应用程序不包含标准模块。标准模块可以包含公有或模块级的变量、常量、类型、外部过程和全局过程的全局声明或模块级声明。缺省时,标准模块中的代码时公有的,任何窗体或模块的事件过程或通用过程都可以调用它。在许多不同的应用程序中可以重用标准模块,在标准模块中可以定义通用过程,但不可以定义事件过程。

  6. 5.1.3 类模块    在VB中,类模块是面向对象编程的基础,文件名以.Cls扩展名。程序员在类模块中编写代码建立新对象,这些新对象可以包含自定义的属性和方法,可以在应用程序中使用。类模块与标准模块的不同之处在于标准仅仅含在代码,而模块既含有代码又含有数据。

  7. 5.1.4 VB过程分类 1. 子过程 1) 事件过程    事件过程由VB自行声明,用户不能增加或删除。当用户对某个对象发出一个动作时,Windows会通知VB产生了一个事件,VB会自动地调用与该事件相关的事件过程。即当对象对一个事件的发生作出认定时,VB便会自动地用相应于事件的名字调用该事件的过程。因为名字在对象和代码之间建立了联系,因而说事件过程是依附于窗体和控件上的。 事件过程的常用格式如下: Private Sub <对象名>_<事件名( [<形参表>] )> <语句系列> End Sub

  8. 2) 通用过程    通用告诉应用程序如何完成一项指定的任务,一旦确定了通用过程,就必须由应用程序来调用。其格式如下: [Private|Public] Sub <过程名>(<参数表>) <语句系列> End Sub    在下图中定义了一个用于计算矩形面积的通用过程Recarea,在主调程序中只要提供矩形的长和宽参数,就可计算出矩形的面积。 图5-3 通用过程

  9. 2. 函数过程 1) 系统函数 VB为了简化程序设计,提供了许多内部函数供设计者调用,如Abs( ),Int( ),ASC( ),MID( )等。 2) 用户自定义函数    除了有固定功能的系统函数之外,还允许用户编写自己的函数过程,被称为用户自定义函数。函数过程的格式如下: [Private|Public] Function <函数过程名>(<参数表>) [As <类型>] <语句> End Function

  10. 5.2子过程的定义和调用 5.2.1创建子过程 建立通用过程有两种方法:直接在“代码”编辑窗口中输入过程代码或使用“添加过程”对话框。 1.在“代码”编辑窗口中输入    在“代码”编辑窗口中,把光标定位在已有过程的外面,然后按如下格式输入通用过程: [Private|Public] [Static] Sub <函数名>([<形参表>]) <语句系列> [Exit Sub] [<语句系列>] End Sub } 子过程体

  11. 关键字说明: 1)Public|Private    可以将子过程放入标准模块、类模块和窗体模块中。按照缺省规定,所有模块中的子过程为Public(公有的),这样在应用程序中可随处调用它们。如果选用Private,则只有该过程所在模块中的程序才能调用该过程。 2) Static    若使用Static关键字,则该过程中的所有局部变量的存储空间只分配一次,切这些变量的值在整个程序运行期间都存在,即在每次调用该过程时,各局部变量的值一直存在;若省略Static,过程每次被调用时重新为其变量分配存储空间,当该过程结束时释放其变量的存储空间。 3) 过程名    过程名的命名规则与变量名相同,长度不超过40个字符。一个过程名只能有唯一的名字,在同一模块中,同一名称不能既作Sub过程名又作Function函数过程名。 4) 语句系列    是过程的过程体,语句系列中可以用一个或多个Exit Sub语句从过程中退出。

  12. 5) 形参表 形参表中的语法为: [ByVal] 参数名1 [As 类型名],[ByVal] 参数名2 [As 类型名],…, 其中ByVal表明该参数是值传递方式。    形参表中出现的参数称为形式参数,简称形参。它并不代表一个实际的存在变量,也没有固定的值。类似于变量声明,它指明了从调用过程传递给过程的变量个数和类型,各变量名之间用逗号凤。其中的形式参数被缺省为具有Variant数据类型,最好将形式参数声明为一个数据类型。在调用此过程时被一个确定的值所代替。形式参数的名字并不重要,重要的是其所表示的关系和调用时所给定的实际参数。

  13. 2.使用“添加过程”对话框    使用“添加过程”对话框建立过程的步骤为: (1) 打开要添加过程的代码编辑窗口。 (2) 执行“工具”菜单中的“添加过程”命令,打开“添加过程”对话框,如下图所示。 图 5-4 过程添加对话框

  14. (3) 在“名称”文本框中输入过程名。从“类型”中选择“子程序”类型。从“范围”组中选择范围,相当于使用Public或Private关键字。 (4) 单击口“确定”按钮。    使用这个方法建立一个过程模板,具体的要求,程序员可以修改它,从而建立自己的过程。

  15. 5.2.2调用子过程    建立子过程的目的就是减少重复代码,将公共语句放入分离开的子过程,并由事件过程来调用它。    每次调用过程都会执行Sub和End Sub之间的语句系列。Sub过程以Sub开始,以End Sub结束。当程序遇到End Sub时,将退出过程,并立即返回到调用语句的后续语句中。

  16. 1.调用方法   调用Sub过程有两种方法: (1) 使用Call语句:Call <过程名> ([<实参表>]) (2) 直接使用过程名:<过程名> ([<实参表>]) 2.使用说明 (1) <实参表>是实际参数表,参数与参数之间用逗号分隔。 (2) 当用Call语句调用执行过程时,其过程名后必须加括号,若有参数,则参数必须放在括号之内。 (3) 若省略Call关键字,则过程名后不能加括号,若有参数,则参数指甲跟在过程名之后,参数与过程名之间用空格分隔,参数与参数之间用逗号分隔。   例如,以下两个语句都调用Recarea过程: Recarea 6,7 Call Recarea(6,7)

  17. 此处还可以这样调用Recarea A,B 3.实例应用 实例1:编写一个计算矩形面积的Sub过程,然后调用该过程计算矩形面积。 Private Sub Form_Click() Dim A As Single, B As Single此处还可以这样调用Recarea A,B A = Val(InputBox("请输入矩形长度?")) B = Val(InputBox("请输入矩形宽度?")) Call Recarea(A, B) End Sub Sub Recarea(Rlen As Single, Rwid As Single) Dim Area As Single Area = Rlen * Rwid MsgBox "总面积是 " & Area '输出矩形面积 End Sub 在以上实例中,子过程Recarea用来计算矩形面积并显示计算结果,主调程序Form_Click提供实际参数A、B,分别为矩形的长和宽。当执行到主调程序中的语句Call Recarea子过程时,程序流程进入Recarea子过程内部,实际参数A、B分别传递给形式参数Rlen,Rwid,直到遇到End Sub语句才结束Recarea子过程,返回到主调程序Form_Click中。

  18. 5.3 函数过程的定义和调用   函数是过程的另一种形式,当过程的执行返回一个值时,使用函数就比较简单。Function过程和内部函数一样,可以在程序或函数嵌套中使用。

  19. 5.3.1创建用户自定义函数过程   与Sub过程一样,Function过程也时一个独立的过程,可读取参数、执行一系列语句并改变其参数的值。创建用户自定义函数过程有两种方法:直接在“代码”编辑窗口中输入函数过程代码或使用“添加过程”对话框。

  20. 函数过程体 1.在“代码”编辑窗口中输入    在“代码”编辑窗口中,把光标定位在已有过程的外面,然后按如下格式输入函数过程:函数过程体 [Private|Public] [Static] Function <函数过程名>([<形参表>]) [As <类型>] <语句系列> [<函数名>=<表达式>] [Exit Function] [<语句系列>] [<函数名>=<表达式>] End Function 说明: 1) Public|Private    与在子过程一样的作用范围。 2) Static    与在子过程一样的作用。

  21. 3) 函数过程名    即Function过程的名字。函数过程的命名规则与变量名相同,长度不超过40个字符,同样,一个过程名只能有唯一的名字在同一模块中,同一名称不能既作Function函数过程名又作Sub过程名。As <类型>指定Function过程返回值的类型,可以是Integer,Long,Single,Double,Currency,String或Boolean。如果没有As字句,缺省的类型为Variant。 4) 语句系列    是函数的过程体,语句系列中可以用一个或多个Exit Function语句从函数中退出。 5) 形参表    形参表的含义与Sub相同。

  22. 6) 表达式    表达式的值是函数返回的结果。在程序中,通过赋值语句将值赋给函数名,该值就是Function过程返回的值。如果在Function过程中省略了“<函数名>=<表达式>”,则该过程返回一个默认值:数值函数过程返回0,字符串函数过程返回空字符串。因此,为了能使一个Function过程完成所指定的操作,通常要在过程中为函数赋值。 2.使用“添加过程”对话框    使用“添加过程”对话框建立过程的步骤与添加子过程步骤一致,只是在“添加过程”对话框中选择类型为“函数”即可。

  23. 5.3.2调用函数过程 1.调用方法    函数的调用比较简单,可以像使用VB内部函数一样来调用Function过程,只需要在表达式中写上它的名字。其语法格式如下:    变量=函数名(实参1,实参2,实参3,…,实参n)    显然,与调用子程序的方法不同,自定义函数的调用遵循内部函数(如Sin、Abs、ASC等)的调用规则,实参也必须用圆括号括起来。 2.使用说明    实参可以是常量、变量、表达式或数组变量名。数据的类型应与子程序定义时的参数类型一致。当子程序的形参传送方式是地址传递时,调用时的实参必须是变量,不允许是常量或表达式。   例如: a=Myfunction(5,10,1)

  24. 3.实例应用 实例2求1到6的阶乘之和,即1!+2!+…+6! Function fact(x As Integer) As Long Dim P As Long, I As Integer P = 1 For I = 1 To x P = P * I Next I fact = P End Function Private Sub Command1_Click() Dim sum As Long, I As Integer For I = 1 To 6 sum = sum + fact(I) Next I Label2.Caption = sum End Sub 以上实例中的fact函数用来完成x!的计算,主调程序Command1_Click用语句sum = sum + fact(I)来完成函数fact的调用,将实参I的值传递给形参x,在函数fact中赋值语句fact = P将x!的值通过函数名返回到主调程序中。在主调程序的循环体循环6次就完成了1!,2!,…,6!的计算,并进行求总和,并总和在标签Label2中显示。

  25. 5.3.3函数过程与子过程的区别    函数过程与子过程的区别如下: 1)适用范围    把某功能函数定义为函数过程或子过程,没有严格的规定,但只要能用函数过程定义的,一定能用子过程定义,反之不一定。因此子过程比函数过程适用面积广。但当只需要返回一个值时,习惯用函数过程,当需要返回多个值时,习惯用子过程。 2)返回值    函数过程有返回值,函数过程名也就有类型,同时在函数过程体内必须对函数过程名赋值。子过程名没有值,子过程名也就没有类型,不能在子过程体内对子过程名赋值。 3.实例应用 实例3:VB提供了一个标准函数Replace,也就是完成查找与替换的功能。现在分别用用户自定义子程序和函数过程来实现。

  26. 这三条语句是否能改成: Call sMyReplace(Text1, Text2, Text3) Public Function MyReplace(s$, OldS$, NewS$) As String Dim i%, lenOldS% lenOldS = Len(OldS) i = InStr(s, OldS) Do While i > 0 s = Left(s, i - 1) + NewS + Mid(s, i + lenOldS) i = InStr(s, OldS) Loop MyReplace = s End Function Public Sub sMyReplace(s$, OldS$, NewS$) Dim i%, lenOldS% lenOldS = Len(OldS) i = InStr(s, OldS) Do While i > 0 s = Left(s, i - 1) + NewS + Mid(s, i + lenOldS) i = InStr(s, OldS) Loop End Sub Private Sub Command1_Click() Dim str As String这三条语句是否能改成: Call sMyReplace(Text1, Text2, Text3)? Print MyReplace(Text1, Text2, Text3) str = Text1 Call sMyReplace(str, Text2, Text3) Text1.Text = str End Sub   在Command1_Click中,替换后的值通过函数名返回,而在子过程中只有通过变量str作为数据通道来传递。特别指出,对象属性不能完成地址方式的传递。

  27. 5.4 过程调用中的参数传递    调用过程的目的,就是在一定的条件下完成某一工作或计算某一数值。外界要把条件告诉过程,或者过程要把某些结果报告给外界,这就是过程与外界的通信。过程与外界的通信有两种方式:通过非局部变量或通过参数。在过程体中使用非局部变量(如全局变量),就是直接处理外界的量。由于这种量在过程内、外都能用,通信不成问题。    调用过程时可以把数据传递给过程,也可以把过程中的数据传递回来。在调用过程中,要考虑调用过程和被调用过程之间的数据是如何传递的。通常在编制一个过程时,要考虑它需要输入哪些量,进行处理后输出哪些量。正确地提供一个过程的输入数据和正确地引用其输出数据,时使用过程的关键问题,也就是通过调用过程和被调用过程之间的数据传递问题。

  28. 5.4.1形式参数与实际参数 1. 形式参数    形式参数是指在定义过程时,出现在Sub或Function语句中变量名,是接收数据的变量。形式参数表中的各个变量之间用逗号分割。形式参数表中的变量类型可以是合法的简单变量,也可以是数组如A(),但不能是定长字符串。即在形参表中只能用如Str1 As String之类的变长字符串作为形式参数,不能用Str1 As String*40之类地定长字符串作为形式参数,但定长字符串可以作为实际参数传递给过程。 2. 实际参数    实际参数是指在调用Sub或Function过程时,传递给Sub或Function 过程地常量、变量或表达式。实参表可由常量、表达式、合法的变量名、数组名(后跟左、右括号)组成,实参表中各参数用逗号分隔。    形式参数与实际参数的对应关系用下例图5-5进行示意:

  29. 实际参数 形式参数 调用过程: Call Sub1(23, A(), "VB6.0", rest) 被调用过程: Sub Sub1(a As Integer, aa() As Single, bb As String, cc As Long) 图 5-5 形参与实参的对应关系   在定义过程时,形式参数为实际参数保留位置。在调用过程时,实际参数被插入对应形式参数变量处,第1个形式参数接收第1个实际参数的值,第2个形式参数接收第2个实际参数的值,依此类推。如上图中,调用过程提供实际参数23、A()、"VB6.0"、rest,被调子过程Sub1提供形式参数aa、a()、bb、cc。当执行调用时,实参23传递给a,实参A()传递给aa(),实参"VB6.0"传递给bb,实参rest传递给cc。在调用时完成形式参数与实际参数的结合,即把实际参数传递给形式参数,然后按形式参数执行被调用的过程。

  30. 5.4.2值传递和地址传递 参数传递的方式有两种:值传递和地址传递。 1. 值传递    如果在定义形式参数时使用了ByVal,或者在调用语句中的实际参数是常量或表达式,那么实参与形参之间数据传递方式是值传递。    在调用过程时,当实参是常量时,直接将常量值传递给形参变量中;当实参是变量时,仅仅将实参变量的值传递给形参变量。然后执行被调过程,在被调过程中,即使对形参发生改变也不会影响实参值的变化。 2. 地址传递    按地址传递参数,就是将实参的地址传递给相应的形参,形式参数与实际参数使用相同的内存地址单元,这样通过调用被调程序可以改变实参的值。在进行地址传递时,实际参数必须是变量,常量或表达式无法进行地址传递。系统缺省的参数传递方式是按地址传递。

  31. ByVal 传值 b 传地址 a 实参 50 20 a中的初值为20,调用后随着y 的改变而改变 x y 形参 50 200 3.实例应用    下面是一个既有值传递又有地址传递的实例。 实例4:先对a、b赋一个初值,然后调用子过程P1,因参数的传递方式不同,a、b参数的原值发生了变化。程序清单如下: Private Sub Form_Click() Dim a As Integer, b As Integer a = 20: b = 50 p1 a, b Print "a="; a, "b="; b End Sub Sub p1(x As Integer, ByVal y As Integer) x = x * 10 y = y + 20 End Sub 图5-6 两种参数传递方式   该程序实参是a,b,被形参是x、y,其中x是地址传递方式,y是值传递方式。当单击窗体,调用p1 a, b语句后,两种参数调用方式见图5-6。实参a的地址传递给形参x,也就是实参a与 形参x共同占用一个内存单元,当对形参x执行语句x = x * 10后,a,x的值都变成200。而实参b仅仅将值传递给形参y,当对形参y执行语句y = y + 20后,形参y的值变成70,但b的值仍然是50。因此单击窗体运行程序后,窗体上显示结果a = 200 ,b = 50。

  32. 4.实参与形参结合时应注意的问题 1)个数、顺序、类型三一致。    实参表与实参表中变量名不必相同,但两表中的个数必须相同,而且各实际参数的书写顺序必须与相应形式参数的类型的要一致。 2)形参是值传递,对应实参可以是表达式、常量、数组元素。 3)形参是地址传递,对应实参只能是简单变量,而且是声明了与形参一致的类型。 4)数组、记录类型、对象只能是地址传递。 5)当实参是对象的属性时,是值传递,即使形参是地址传递方式,也不会改变实参的值,也就是不会改变对象的属性值。

  33. 5.4.3使用参数 1. 使用可选参数 1)定义可选参数    一个过程在声明时定义了几个形参,则在调用这个过程时就必须使用相同数量的实参数。Visual Basic允许在形参前面使用Optional关键字把它设为“可选参数”。Optional关键字可以与ByVal、ByRef关键字同时修饰一个参数。如果一个过程的某个形参为可选参数,则在调用此过程时可以不提供对应于这个形参的实参。如果一个过程有多个形参,当它的一个形参设定为可选参数时,这个形参之后所有的形参都应该用Optional关键字定义为可选参数。 2)调用可选参数    调用一个具有多个可选参数的过程时,可以省略它的任意一个或多个可选参数。如果被省略的不是最后一个参数,它的位置要用逗号保留。如Call Sub1(int1,,int2)表明省略了第二个参数。若一个可选参数没有被省略,则调用语句的实际参数与非可选参数相同。未得到实参值的形参在调用时被赋以形参类型的默认值。

  34.    例题: 下面的事件过程在调用一个具有可选参数的过程时,省略了相应的实参。 Private Sub Command1_Click() '省略了第二个参数 Call mysub1("abcd") End Sub Sub mysub1(var1 As String, Optional var2 As Integer) '第二个参数可选 Text1.Text = var1 Text2.Text = var2 '当前情况下,由于var2没有得到相应实参的值,因此var2在调用时被赋以Integer类型的默认值,即var2的值为0。 End Sub

  35. 2.可选参数的缺省值    前面讲过,一个可选参数被省略时,调用时赋给形参的是它的数据类型的默认值。如果希望在省略一个可选参数时,能够赋给形参一个其他特定的值,就要用到给可选参数设定默认值的方法。可以在声明过程时,通过给可选参数赋值的方法来设定可选参数的默认值。当调用此过程时即使未提供相应实参的值,形参也会以它的默认值来运行程序。 实例5: Private Sub Command1_Click() '省略了第二个参数 Call mysub1("abcd") End Sub Sub mysub1(var1 As String, Optional var2 As Integer = 10) '第二个参数可选,设定默认值时要注意,赋值号要放在类型名称的后面。 Text1.Text = var1 Text2.Text = var2 '此时将var2变量的值10赋给Text2.Text End Sub

  36. 5.4.4数组作为参数传递 1.数组传递原则    整个数组可以作为一个实参传递给过程,但是要求过程在声明时相应的形参应加空格来表明是数组。调用时,相应的实参必须是数组,只要数组名,不必加括号。    在调用子过程或者函数过程时,可以将数组或数组元素作为参数进行传递。使用数组元素传递是值传递方式。传递整个数组时,在实际参数与其所对应的形式参数都必须写上所要传递地数组名称和一对小圆括号,如arr(),在被调程序中,不可再用Dim语句来定义所要传递地数组。数组作为参数时必须是按地址传递的,不能使用ByVal关键字修饰。形参数组与实参数组的数据类型应一致。

  37. Sub subP(b() As Integer) For i = 1 To 4 b(i) = 2 * i Next i End Sub Private Sub Command1_Click() Dim a(1 To 4) As Integer a(1) = 5 a(2) = 6 a(3) = 7 a(4) = 8 subP a '或者subP a() For i = 1 To 4 Print a(i) Next i End Sub    上例中主调程序Command1_Click中调用语句subP a,实参数组a可以带括号也可以省略,形参数组b一定要带上空的括号,不能加下标。    如果要传递数组中的某一元素,则在Call语句中只需直接写上该数组元素。例如:Call sub1(arr(3),10)。

  38. 2.实例应用 实例6:折半查找    已知一个数组a(m To n)中各元素的值是从小到大排列的,其中有一个元素的值为b。编程求出这个元素的下标。    对于这个问题,最容易想到的方法就是“顺序查找法”。下面的函数Search1就是使用顺序查找法,从数组a中查找值为b的元素,并返回其下标。    顺序查找法是从数组的第一个元素开始逐个地比较,虽然编程简单,但是执行效率却很低。在一个有k个元素的数组中查找一个值,平均需要进行k/2次比较。如果数组中有15个元素,则平均比较7.5次。    相比之下,折半查找法是比较高效的查找方法。    折半查找的思路是:先拿被查找数与数组中间的元素进行比较,如果被查找数大于元素值,则说明被查找数位于数组中的后面一半元素中。

  39.    如果被查找数小鱼数组中中间元素值,则说明被查找数位于数组中的前面一半元素中。接下来,只考虑数组中包括被查找数的那一半元素。拿剩下这些元素的中间元素与被查找数进行比较,然后根据所在的大小,再去掉那些不可能包含被查找值的一半元素。这样,不断地减少查找方位,直到最后只剩下一个数组元素,那么这个元素就是被查找的元素。当然,也不排除某次比较时,中间的元素正好是被查找元素。折半查找中应该注意的是,如果数组中(或中间过程中)的元素个数是偶数,就没有一个元素正好位于中间,这时取中间偏前或中间偏后的元素来与被查找值进行比较不会影响查找结果的正确性。   如果被查找数小鱼数组中中间元素值,则说明被查找数位于数组中的前面一半元素中。接下来,只考虑数组中包括被查找数的那一半元素。拿剩下这些元素的中间元素与被查找数进行比较,然后根据所在的大小,再去掉那些不可能包含被查找值的一半元素。这样,不断地减少查找方位,直到最后只剩下一个数组元素,那么这个元素就是被查找的元素。当然,也不排除某次比较时,中间的元素正好是被查找元素。折半查找中应该注意的是,如果数组中(或中间过程中)的元素个数是偶数,就没有一个元素正好位于中间,这时取中间偏前或中间偏后的元素来与被查找值进行比较不会影响查找结果的正确性。    下面的函数Search2使用折半查找的方法从数组a中查找b值所在的元素,并返回它的下标。

  40. Function search2(a() As Integer, b As Integer) As Integer Dim m, n, int1 As Integer m = LBound(a) n = UBound(a) Do int1 = (m + n) \ 2 '找到中间元素的下标 If b < a(int1) Then ' 被查找值位于前半部分 n = int1 - 1 ElseIf b > a(int1) Then ' 被查找值位于后半部分 m = int1 + 1 Else ' 被查找值恰好是中间元素 search2 = int1 Exit Function End If If m = n Then '只剩1个元素 search2 = m Exit Function End If Loop End Function

  41. 分析程序,当被查找值正好是数组的第一个或最后一个元素时,函数Search2能否正确执行?分析程序,当被查找值正好是数组的第一个或最后一个元素时,函数Search2能否正确执行?   虽然使用折半查找方法的编程稍微复杂一些,但是它的查找效率比顺序查找高得多。在k个元素中查找一个值,进行比较的次数不会超过。如果k为15,则折半次数不会超过4次。当k的值很大时,折半查找的优势就更能体现出来了。 折半查找的局限在于,数组中的元素必须是排序了的(递增或递减)。否则,折半查找就无能为力了,只能尝试其他的查找方法,比如,顺序查找法。 3.注意事项 如果实参是一个动态数组,则相应的形参也可以被看做动态数组,在子过程中可以使用语句重新定义。因为数组是按地址传递的,所以,在子过程中改变数组维数、下标上下界以及元素值,同时也改变了父过程的数组。

  42. 5.4.5值传递和地址传递的区别 采用值传递只能从外界向过程(函数)传入信息,但不能传出,正是不能传出,过程结束后,形式参数的值就不会影响外界的任何量,因此说,值传递比较安全;而采用地址传递既能传入又能传出,是一种数据通信方式。   值传递和地址传递的一个重要区别:值传递对应的实参是表达式,而地址传递对应的实参只能是变量。

  43. 实例6:通过值传递和地址传递来求出1!+2!+…+5!的值实例6:通过值传递和地址传递来求出1!+2!+…+5!的值 Private Function multiply1(n As Integer) As Integer '地址传递 multiply1 = 1 Do While n > 0 multiply1 = multiply1 * n n = n - 1 Loop End Function Private Sub Command1_Click() Dim sum As Integer, i As Integer For i = 5 To 1 Step -1 sum = sum + multiply1(i) Next Print Print "参数传递方式:地址传递" Print "sum="; sum End Sub Private Function multiply2(ByVal n As Integer) As Integer '值传递 multiply2 = 1 Do While n > 0 multiply2 = multiply2 * n n = n - 1 Loop End Function Private Sub Command2_Click() Dim sum As Integer, i As Integer For i = 5 To 1 Step -1 sum = sum + multiply2(i) Next Print "参数传递方式:值传递" Print "sum="; sum End Sub

  44. 5.5过程和变量的作用域 5.5.1 变量的作用范围    变量的作用范围(作用域)指变量能被某一过程识别的范围。当一个应用程序出现多个过程或函数时,在它们各自的子程序中都可以定义自己的常量、变量,但这些常量或变量并不可以在程序中到处使用。    从表1可以看出,在VB中,可以在过程或模块中声明变量,根据声明变量的位置,变量分为两类:过程级变量(局部变量)和模块级变量(窗体级变量和全局变量)。

  45. 1.过程级变量    在一个过程内部使用或关键字声明变量时,只有该过程内部地代码才能访问或改变该变量的值。过程级变量的作用范围限制在该过程内部。例如: Dim a As Integer, b As Single Static s1 As String    如果在过程中未作说明而直接使用某个变量,该变量也被当成过程级变量。用Static说明的变量在应用程序的整个运行过程中一直存在,而用Dim说明的变量只在过程执行时存在,退出过程后,这类变量就会消失。过程级变量通常用于保存临时数据。    过程级变量属于局部变量,只能在建立的过程内有效,即使时在主程序中建立的变量,也不能在被调用地子过程中使用。即局部变量的作用域仅限于它们自己所在的过程,使用局部变量的程序比仅是使用全程变量的程序更具有通用性。

  46. 例题7过程级局部变量实例   程序代码清单如下: Private Sub Command1_Click() Dim a As Integer, b As Integer, c As Integer '过程级局部变量 a = 5: b = 3 Print Print Tab(15); "a"; Tab(25); "b"; Tab(34); " c = a * b" Print "调用Prod前"; Tab(14); a; Tab(24); b; Tab(34); c Call Prod Print "调用Prod后"; Tab(14); a; Tab(24); b; Tab(34); c Print Print "调用Sum前"; Tab(14); a; Tab(24); b; Tab(34); c 'Print Call Sum Print "调用Sum后"; Tab(14); a; Tab(24); b; Tab(34); c End Sub Sub Prod() '通用过程 Dim a As Integer, b As Integer, c As Integer '过程级局部变量 c = a * b Print "Prod子程序"; Tab(14); a; Tab(24); c; Tab(34); c End Sub Sub Sum() '通用过程 Dim a As Integer, b As Integer, c As Integer '过程级局部变量 c = a + b Print "Sum子程序"; Tab(14); a; Tab(24); c; Tab(34); c End Sub

  47.    程序运行结果如下图所示,从运行结果可以看出,主程序中的变量没有带到子过程中。   程序运行结果如下图所示,从运行结果可以看出,主程序中的变量没有带到子过程中。    在编写一个较复杂的程序时,可能有多个过程或函数。在书写过程(函数)说明时,往往而且应该把注意力集中在一个相对独立的子过程内。其中所用到的变量名如果都是局部的,则无论怎样处理都不会影响到外界。如果用到非局部量,一经改变就会影响到外界,考虑不周时容易引起麻烦,所以,为安全起见,过程(函数)体内应尽可能用局部变量。 图5-7 程序运行结果

  48. 2.模块级变量    在模块的通用段中声明的变量属于模块级变量。模块级变量分为窗体模块级和全局级。 1)窗体模块级变量    窗体模块级变量在声明它的整个模块的所有过程中都能使用,但其他模块却不能访问该变量。声明方法是在模块的通用段中使用Private或Dim关键字声明变量例如: Private s As String Dim a As Integer, b As Single 2)全局级变量    全局级变量在所有模块的所有过程中都能使用的内存变量。它的作用范围是整个应用程序。全局级变量的声明方法是在模块的通用声明段中使用关键字Public来声明变量。例如: Public x As Integer, y As Double    把变量定义为全局变量虽然很方便,但这样会增加变量在程序中被无意修改的机会,因此,如果有更好的处理变量的方法,就不要声明全局变量。

  49. 例题: Public a As Integer, b As Integer, c As Integer '写在"通用"的"声明"中 Private Sub Command1_Click() a = 5: b = 3 Print Print Tab(15); "a"; Tab(25); "b"; Tab(34); " c = a * b" Print " 调用Prod前"; Tab(14); a; Tab(24); b; Tab(34); c Call Prod Print " 调用Prod后"; Tab(14); a; Tab(24); b; Tab(34); c Print Print Tab(15); "a"; Tab(25); "b"; Tab(34); " c = a * b" Print " 调用Sum前"; Tab(14); a; Tab(24); b; Tab(34); c 'Print Call Sum Print " 调用Sum后"; Tab(14); a; Tab(24); b; Tab(34); c End Sub Sub Prod() '通用过程 c = a * b Print " Prod子程序"; Tab(14); a; Tab(24); c; Tab(34); c End Sub Sub Sum() '通用过程 c = a + b Print " Sum子程序"; Tab(14); a; Tab(24); c; Tab(34); c End Sub     程序运行结果如图所示。从程序运行结果可以看出,在模块级中用声明的全局变量a、b、c,在各个过程中都能访问和修改。 图5-8 程序运行结果

More Related