第 8 章 过程.

Slides:



Advertisements
Similar presentations
编程加工 信息的. 趣味导入拓展提升大显身手总结反思学以致用 传说古代印度有个国王叫舍罕,他很迷恋棋类,而 宰相达依尔是个聪明的大臣,发明了国际象棋。国王玩 得爱不释手,决定奖赏宰相。达依尔说:陛下,我别无 他求,请你在这张棋盘的第一个格子里赏我 1 粒麦子; 在第二个格子里赏我 2 粒麦子;在第三个格子里赏我.
Advertisements

第二章 VB程序设计基础 第1节 Visual Basic 概述 1.1 Visual Basic简介 1.2 面向对象的程序设计概念
第2章 Visual Basic 6.0编程基础 (第一部分)
第四章 控制结构.
第 7 章 文 件.
程式語言(I)- Visual Basic 6.0 第 9 章 結構化程式設計
Access数据库程序设计 总复习.
高等医药院校药学类第三轮规划教材——大学计算机基础
第五章 数组.
Visual Basic程序设计.
BLANK overview.
程式語言Visual Basic 變數的可視範圍
Visual Basic 2010 程式設計16堂特訓 第七堂 VB的迴圈流程控制.
課程名稱:程式設計 授課老師:________
Visual Basic 6.0 學習範本 第三章 基本資料型態.
第6章 数 组 6.1 一维数组 6.2 控件数组 6.3 二维数组.
第二章 Visual Basic语言基础.
講師:戴志華 國立台灣大學電機工程研究所 Visual Basic 程式設計 講師:戴志華 國立台灣大學電機工程研究所.
数组 第 6 章.
第5章 数组 Visual Basic程序设计.
Visual Basic程序设计 第七章 数组
1、数组的概念 2、静态数组 3、动态数组 4、数组的基本操作 5、控件数组
程式語言 -Visual Basic 變數、常數與資料型態.
1 巨集 2 資料型態 3 物件、屬性、方法與事件 4 陳述式與副函式 5 其他注意事項 6 範例
Visual Basic程序设计 第八章 过程 -子程序和函数
过程 第 7 章.
ASP动态网页设计实用教程 主讲教师: 开课单位:.
初识Visual Basic.
算法与程序设计.
第4章 程序控制结构与算法基础.
新觀念的 VB6 教本 第七章 讓程式轉彎的控制敘述.
Visual Basic 程序设计教程 机械工业出版社同名教材 配套电子教案 2003 年 6月.
第4章 基本的控制结构 4.1 顺序结构 4.2 选择结构程序设计 4.3 循环结构 4.4 综合实例 退出.
流程控制、陣列 台南市聖功女子高級中學 毛全良.
用计算机模拟闪电形成的尝试 By 金秀儒 物理三班 PB
计算机程序设计强化复习 Visual Basic 6.0.
Visual Basic 程序设计 教师:王 杨 电话:
第十二章 多模組與多專案.
程式語言Visual Basic 傳址與傳值
3.5 用递归法解决问题 黄学鸿.
第12章 VBA模块设计.
丙級電腦軟設-VB程式設計 資料來源:林文恭研究室 整理:張福生.
新觀念的 VB6 教本 第 6 章 資料型別.
第5章 Visual Basic控制结构 之 常用算法举例
广州市教育局教学研究室编写的 初中《信息技术》第二册第二章 《程序设计初步》
Visual Basic程序设计.
算法与程序设计 周少品.
VB程序设计语言 主讲教师:王 杨.
VB程序设计语言 主讲教师:王 杨.
第三章 VB语言基础 本章重点和难点 3.1 Visual Basic 程序代码的组织方式 3.2 代码行的书写规则
程式設計 Visual Basic簡介 週次:2 建國技術學院 資管系 饒瑞佶 2003年9月17日.
程序设计基础 第 2 章 学习程序设计的基本方法: 多练 模仿.
VB程序设计语言 主讲教师:王 杨.
VB程序设计语言 主讲教师:王 杨.
程式語言(I)- Visual Basic 6.0 第 8 章 模組化程式設計I-副程式與自定函數.
For x = 0 To 9 For y = 0 To 9 z = *x + 10*y …… Next y
江西财经大学信息管理学院 《数据库应用》课程组2007
VB语言程序设计教程.
小结 郭清溥.
经典算法之 冒 泡 排 序.
现代信息技术 微电子技术 计算机技术 传感技术 通信技术 处理、存储信息的技术 传感、采集技术 传递信息的技术
第二章、第三章错题分析.
选择结构设计 第 4 章 程序流程有三种最基本的控制结构,即顺序结构、选择结构和循环结构。
問題解決與流程圖 高慧君 台北市立南港高中 2006年12月22日.
1位选手参加了歌唱比赛,评委们的评分如下:
第5章 数组 5.1 数组概述 5.2 静态数组和动态数组 5.3 数组的基本操作 5.4 控件数组 5.5 数组在自定义数据类型中的应用.
1、过程概述 2、函数过程 3、子过程 4、过程的使用 5、传递参数 6、过程的嵌套
解析算法与枚举算法.
顺序查找与二分查找复习.
算法与Visual Basic程序基础(二)
Presentation transcript:

第 8 章 过程

教学要求 掌握VB的两种过程:事件过程和通用过程 掌握Sub过程的定义 掌握Function过程的定义 掌握过程的调用 掌握参数的传递——按值传递和按地址传递 掌握递归算法 掌握变量的作用域 2

教学内容 8.1 Sub过程 8.2 Function过程 8.3 过程调用 8.4 参数传递 8.5 递归过程 8.6 变量的作用域 8.3 过程调用 8.4 参数传递 8.5 递归过程 8.6 变量的作用域 8.7 程序示例 3

模块化程序设计 基本思想:将一个大的程序按功能分割成一些小模块 特点: 各模块相对独立、功能单一、结构清晰、接口简单 控制了程序设计的复杂性 提高元件的可靠性 缩短开发周期 避免程序开发的重复劳动 易于维护和功能扩充 开发方法: 自上向下,逐步分解,分而治之 4

过程 事件过程 通用过程 子程序过程 Sub 函数过程 Function VB中过程的分类 5

8.1 Sub过程 8.1.1 事件过程 当对象识别某事件后,进行的操作处理——以代码的形式存储在事件过程中。 分类: 窗体事件过程 控件事件过程 6

窗体的事件过程名中不使用其具体名称,而固定用Form 窗体事件固定有“Private”关键字,说明它是模块级的 1 定义事件过程 [形式]: Private Sub Form_事件名([参数列表]) [局部变量和常数声明] 语句块 End Sub 完全由系统决定,用户无权修改 窗体的事件过程名中不使用其具体名称,而固定用Form 窗体事件固定有“Private”关键字,说明它是模块级的 7

2 窗体的Initialize、Load、 Activate、 Gotfocus事件 执行次序: Initialize Load Activate Gotfocus 8

注 意 窗体的Initialize、Load事件发生在窗体被显示之前,其中可放置系统初始化命令,但其中语句有所限制; 注 意 窗体的Initialize、Load事件发生在窗体被显示之前,其中可放置系统初始化命令,但其中语句有所限制; 窗体加载后,只要不被卸载,就不会再执行Initialize、Load事件,但Activate事件会多次发生; 当访问另一窗体上的“非可视”数据或调用其中定义的全局过程时,只会触发该窗体的Initialize事件,而Load事件不触发; 当访问另一窗体上的“可视”数据时,会同时触发该窗体的Initialize和Load事件; 9

控件事件固定有“Private”关键字,说明它是模块级的 3 定义控件的事件过程 [一般形式]: Private Sub 控件名_事件名([参数列表]) [局部变量和常数声明] 语句块 End Sub 由系统决定,用户无权修改 控件的事件过程名中必须使用其具体名称 控件事件固定有“Private”关键字,说明它是模块级的 10

4 建立事件过程 打开“代码编辑器”窗口; 先选定某对象,再选定事件过程; 编辑代码; 过程 对象 11

c 计算: n! = m!(n-m)! Private Sub Command1_Click() n = Val(Text1.Text) m = Val(Text2.Text) k = n t = 1 For i = 1 To k t = t * i Next i s = t k = m s = s / t k = n - m Text3.Text = Str(s) End Sub c n m = m!(n-m)! n! 共同代码 计算k! 能不能简化?

使用函数 Private Sub Command1_Click() Dim m As Integer, n As Integer Dim i As Integer, k As Integer Dim t As Long, s As Long n = Val(Text1.Text) m = Val(Text2.Text) s = fact(n) / (fact(m) * fact(n - m)) Text3.Text = Str(s) End Sub Private Function fact(k As Integer) As Long Dim i As Integer fact = 1 For i = 1 To k fact = fact * i Next i End Function 使用函数 函数调用(三次) 函数定义 计算k! 13

过程的引入: 在以下两种情况下,经常使用自定义过程: (1)应用程序中出现较频繁的处理,仅仅是每次处理的数据不同而已; (2)程序中比较复杂的算法,独立出来,增强程序的可读性; “过程”的引入使得整个程序的结构更加清晰,模块化更强。 14

8.1.2 通用过程 完成某一特定功能的程序段 ——通用过程(自定义) 必须显式调用方可执行; 分为: 公有过程(Public) 8.1.2 通用过程 完成某一特定功能的程序段 ——通用过程(自定义) 必须显式调用方可执行; 分为: 公有过程(Public) 私有过程(Private) 15

1 通用Sub过程的定义 [一般形式]: [Private|Public] [static] Sub <过程名>([<参数列表>]) <过程体> End Sub [说明]: (1) 以Sub开头,End Sub结束,,中间是过程体——包括变量声明和语句块; (2) 以Private为前缀的过程是模块级的,以Public为前缀的过程是应用程序级的,缺省默认是Public; (3) Static 选项说明过程中的局部变量是静态变量; (4) 过程名的命名规则和变量名相同,在同一个模块中,过程名必须是唯一的; 16

说 明 (5) 参数列表中的参数称为形式参数,可以没有,但无参数时圆括号不能省略;有多个参数时,参数之间用逗号间隔; (6)参数说明格式: 说 明 (5) 参数列表中的参数称为形式参数,可以没有,但无参数时圆括号不能省略;有多个参数时,参数之间用逗号间隔; (6)参数说明格式: [Optional][ByVal|ByRef] <变量名>[()][As <数据类型>] 其中: a) 若参数是数组,则在变量名后面加一对圆括号,但无维界定义 b) ByVal:指明参数传递方式是传值; c) ByRef:指明参数传递方式是传地址,为缺省值; d) 若参数是字符型的,必须是不定长字符串; e)Optional:参数是可选的,必须定义在必选参数后面。 (7) 当过程调用结束,即执行到End Sub语句,系统自动返回调用程序的调用语句处,执行调用语句的下一条语句; (8) 过程不能嵌套定义,但可嵌套调用; (9)Exit Sub语句的功能是提前退出过程调用,返回调用语句。 17

该通用过程实现交换功能,包含两个参数,均是ByRef形式的参数。 例: Private Sub Exchange(x As Integer,y As Integer) Dim Temp As Integer Temp=x : x=y : y=Temp End Sub 该通用过程实现交换功能,包含两个参数,均是ByRef形式的参数。 18

2 建立通用Sub过程 方法一:在“代码编辑窗口”的“通用”中自行输入; 方法二:进入代码编辑器窗口,执行“工具”菜单的“添加过程”,在“添加过程”对话框中输入定义过程的名称、类型和范围后单击“确定”按钮,系统会自动在代码窗口添加自定义过程的框架。 19

3 Sub过程调用 注意 :一个过程或函数可以被调用多次; 必须在事件过程或其它通用过程中显示调用。 Private Sub sub2(形参表) …… 过程语句 End Sub Private Sub sub1() …… Call Sub2(实参表) End Sub ② ③ ① ④ ⑤ 主调程序 被调过程 注意 :一个过程或函数可以被调用多次; 20

Call Fact(x) Fact x Sub过程调用 P164 [格式二]: <过程名> [<实在参数表>] [功能]:对已定义的过程进行调用。 如: P164 Call Fact(x) Fact x 21

说 明 (1)调用的过程必须是已经定义的,否则系统会出现“子程序或函数未定义”的信息提示; (2)实在参数可以是常量、变量或表达式; (3)实在参数的数目及类型要和定义时必选参数保持一致,否则系统会出现“参数不可选”的信息提示,参数之间用逗号间隔; (4)若子程序没有参数,则格式一中的括号可以省略; (5)格式一和格式二的区别在于:格式二的参数表无须括号,而是和过程名之间用空格隔开; 22

例8-2 试编写一个找出任意一个正整数的因子的程序 例8-2 试编写一个找出任意一个正整数的因子的程序 P165 23

程序说明: 定义子程序factor求因子,该子程序定义了两个参数,来传递求因子实现前的原始数据和返回功能实现后的结果数据; Option Explicit Private Sub Command1_Click() Dim inta As Integer, st As String inta = Text1 Call factor(inta, st) Text2 = st End Sub 调用过程factor Private Sub factor(ByVal n As Integer, s As String) Dim i As Integer For i = 1 To n - 1 If n Mod i = 0 Then s = s & Str(i) Next i End Sub 定义过程 优点:程序即Sub过程的使用不仅可以缩短程序的长度,还能够使程序的结构更加清楚。 24

例:定义一个通用过程用以求一维数组中的最小值 Private Sub value(a() As Integer, min As Integer) Dim i As Integer min = a(1) For i = 2 To UBound(a) If a(i) < min Then min = a(i) Next i End Sub 25

8 . 2 Function 过程 Function过程的特点是返回一个值,因此我们通常也称之为自定义函数。通常我们利用Function过程得到一个数值或一个字符串或一个逻辑值。 [格式]: [Private|Public] Function <函数名>([参数列表]) [As <数据类型>] <函数体> End Function 函数返回值的类型 函数名=表达式 26

说 明 (1) 以Function开头,以End Function结束,中间是函数体; 说 明 (1) 以Function开头,以End Function结束,中间是函数体; (2)函数名命名规则、参数列表的表示都和Sub过程相同; (3)As 数据类型:函数过程将由函数名返回一个值,值的类型由[As 数据类型]定义; ★ (4) 函数体中一定要有对函数名赋值的语句——函数名=表达式,否则返回相应类型的初值; ★ (5)函数体内可有Exit Function语句——无条件退出函数过程,返回主程序。 (6)Function过程不能嵌套定义,但可嵌套调用。 27

例:定义函数: Private Function f(ByVal x As Integer) As Integer 函数返回值的类型 Private Function f(ByVal x As Integer) As Integer f = 3*x^3-2*x^2+6*x-1 End Function 函数名=表达式 28

传值的参数 例8-1:编写一个求n!的函数。 Private Function Fact(Byval n As Integer) As Long Dim K As Integer Fact=1 If n=0 Or n=1 Then Exit Function Else For K=1 To N Fact=Fact*K Next K End If End Function 函数类型 函数名=表达式 29

2 调用 Function 过程 Call fact(x) Fact x 这两种方法均放弃函数的返回值 [格式]:<函数名>([实在参数表]) [功能]:返回一个函数值。 [说明]: (1)一般情况下,函数的调用出现在赋值语句中,并且在赋值号的右侧; (2)若函数没有参数,函数名后的括号不能省略; (3)虽然VB允许象调用Sub过程那样调用Function过程,但这样调用时系统不返回函数值,建议大家不要使用这种调用方法。 Call fact(x) Fact x 这两种方法均放弃函数的返回值 例如: 30

例:用函数实现求一维数组中的最小值,对比前例(Sub) Private Function min( a( ) As Integer ) As Integer Dim i As Integer min = a(1) For i = 2 To UBound(a) If a(i) < min Then min = a(i) Next i End Sub 函数类型 函数名=表达式 31

可省略,因Prime的初始值就是false 例:定义函数用以判断一个数是否是素数 Private Function Prime(N As Integer) As Boolean Dim i As Integer Prime = False For i = 2 To N-1 If N Mod i = 0 Then Exit For Next i If i =N then Prime = True End Function 可省略,因Prime的初始值就是false 函数名=表达式 32

[例]:S=1!+2!+…+10! 函数调用: S = S + Fact(i) 函数名=表达式 对比p171 Private Sub Form_Click() Dim S As Long, i As Integer For i = 1 To 10 Next i Print ”S="; S End Sub 函数调用: S = S + Fact(i) Private Function Fact(n As Integer) As Long Dim i As Integer Fact = 1 For i = 1 To n Fact = Fact * i Next i End Function 函数名=表达式 33

例8-3:利用函数过程编写一个求两个正整数的最大公约数的程序 P166 Private Function Gcd(ByVal A As Integer, ByVal B As Integer) As Integer Dim R As Integer R = A Mod B Do While R <> 0 A = B B = R Loop Gcd = B End Function Private Sub Form_Click( ) ‘ 主调过程 Dim N As Integer, M As Integer, G As Integer N = InputBox("输入N") M = InputBox("输入M") G = Gcd(N, M) Print N; "和"; M; "的最大公约数是:"; G End Sub 使用赋值语句调用函数 34

8.3.4 调用其他模块中的过程 1、调用其他窗体模块中的公有过程 在Form2中调用 8.3.4 调用其他模块中的过程 1、调用其他窗体模块中的公有过程 [格式]:Call <窗体名>.<过程名>[(<实在参数表>)] [功能]:调用其他窗体模块中定义的公有过程。 Private Sub Form_Click() Dim a As Integer a = 10 Print Form1.Fact(a) End Sub 在Form2中调用 35

2、调用标准模块中的公有过程 [格式]:Call [<标准模块名>.]<过程名>[(<实参表>)] [功能]:调用其他标准模块中定义的公有过程。 [说明]: 若公有过程唯一,则直接调用,不加模块名。 若存在同名的公有过程,则: 调用本模块中过程:直接调用,不加模块名 调用其它模块中过程:必须加模块名。 被调用的函数和过程必须是公有的; 函数也可以这样调用。 36

调用类模块中的过程 不做要求 [格式]: dim democlass as new class1 call democlass.clssub ( [实参表] )] [注意]: 调用类模块中的共有过程,须用该类的某一实例修饰过程。 不做要求 37

8.4 参数的传递 8.4.1 形式参数和实在参数 形式参数: 过程定义时,在过程名后面的圆括号里的一系列变量; 8.4 参数的传递 8.4.1 形式参数和实在参数 形式参数: 过程定义时,在过程名后面的圆括号里的一系列变量; 过程被调用执行时,系统才给形参分配存储空间; 可以是除定长字符串外的任一简单变量; 可以是数组,变量名后接括号; 简称“形参” St As String *3 × St( ) As String *3 √ St As String √ 38

实在参数 主调程序中,调用语句中,出现在过程名后面圆括号里的变量,是实在参数,可以是常量、变量或表达式; 过程调用传递参数时,实参按“位置”和形参结合; 实在参数和形式参数,要求个数一样,位置对应,类型一致,否则会出错; 定长字符串变量可以作为实在参数; 简称“实参” 39

参数结合: 形参 实参 变量 变量、常量、表达式、数组元素 数组 40

举例: Private Sub Form_Click() Dim x as single , st as sting*5 Private sub test(a as single,loc as booleaan,array1() as integer,chr1 as string) … End sub Private Sub Form_Click() Dim x as single , st as sting*5 Dim a(5) as integer Call test (x^2 ,true, a, st ) End sub 定长字符串 表达式 常量 数组 41

举例:写出下列程序执行的结果 Private Sub ExamSub( x as integer,y as integer) x=x+10 : y=y-10 End Sub 过程的先后顺序无所谓 Private Sub Form-click() Dim x as integer, y as integer x=10:y=100 Call ExamSub( y ,x ) Print “x=” ; x ; “y=” ; y End Sub 调用子过程时,进行的实际操作是y=y+10,x=x-10 42

8.4.2 按值传递参数 [格式]:ByVal <变量说明> [传递方式 ]: 8.4.2 按值传递参数 [格式]:ByVal <变量说明> [传递方式 ]: 调用时,系统为形参分配一个临时存储单元,并将实参 的值存储到该临时单元中。 若在被调用的过程体中改变了形参的值,只是改变了临时 存储单元中的数据,对实参的值无任何影响。 43

[参数传值传递]举例: Private Sub Form_Click() Dim M As Integer, N As Integer M = 15: N = 20 Call Value_change(M, N) Print "M="; M, "N="; N End Sub Private Sub Value_change(ByVal x As Integer, ByVal y As Integer) x = x + 20 y = y + 20 Print "X="; x, "Y="; y End Sub 44

传值是单向的: 实在参数 形式参数 调用时,实参将值传递给形参,两者就无任何关联。过程中形参的值发生变化,对实参无任何影响。 45

8.4.3 按地址传递参数 [格式]: ByRef <变量说明> [传递方式]: 系统在调用执行过程时,为形参分配临时存储单元,并将实参的内存单元地址传送给形参,存储在临时存储单元中 在被调用的过程体中一切对形参的操作,都是直接对地址保存在形参中的内存单元中的数据进行的,而实参就是保存在此内存单元中的数据,所以任何对形参的操作也就是对实参的操作; 按地址传递时,形式参数和实在参数共用同一“内存单元”。 46

[参数传址传递]举例:(对比前例) Private Sub Form_Click() Dim M As Integer, N As Integer M = 15: N = 20 Call Value(M, N) Print "M="; M, "N="; N End Sub Private Sub Value(x As Integer, y As Integer) x = x + 20 y = y + 20 Print "X="; x, "Y="; y End Sub 47

传地址是双向的: 实在参数 形式参数 48

举例:计算5!+4!+3!+2!+1! P171 Private Sub Form_Click() Dim Sum As Integer, I As Integer For I = 5 To 1 Step -1 Sum = Sum + Fact(I) Next I Print "Sum="; Sum End Sub Private Function Fact(n As Integer) As Integer Fact = 1 Do While n > 0 Fact = Fact * n n = n - 1 Loop End Function 修改: 方法一:在形参n前加ByVal 方法二:将调用语句中fact(i)改为fact( ( i ) ) 49

注 意 参数有两种传递方式:传值(ByVal)和传地址(ByRef)。 注 意 参数有两种传递方式:传值(ByVal)和传地址(ByRef)。 若调用时实参为常量或表达式,这两种方式没有区别,无论形参定义的是按值传递还是按地址传递,系统都是按传值方式传递 系统在调用时为形参分配一个临时存储单元,将表达式的值计算出来,存储到该临时单元;调用结束,系统收回临时单元。 调用函数或过程时,将单个变量转换成表达式的方法:将变量放在一对括号中。如用Fact((I))的方式调用函数,系统会按传值来处理。 50

注 意 按地址传递时,当实参是变量时,实参与形参必须类型完全一致; 注 意 按地址传递时,当实参是变量时,实参与形参必须类型完全一致; 按地址传递时,当实参是常量或表达式时,VB会自动进行类型转换,然后再传递相应的值(即类型无须完全一致); 在算术表达式中,函数的优先级最高,若表达式中有函数的实参,而函数的参数又是按地址传递的,则函数中有可能改变了实参的值,即改变了表达式中变量的值,会引起混淆。 见例 见例 51

实际的参数传递方式是按值传递,强制转换后, 举例: Private Sub Form_Click() Dim S As Single S=125.5 Call Convert((S),”12”+”.5”) End Sub Private Sub Convert(Inx As Integer,Sing As Single) Inx=Inx*2 Sing=Sing+23 Print “Inx=”;Inx,”Sing=”;Sing 实际的参数传递方式是按值传递,强制转换后, inx =126 sing=12.5 52

举例: a=a+10 : b=b+10 : c=c+10 fun_add=a+b+c End function Private function fun_add(a as integer,b as integer,c as integer) as integer a=a+10 : b=b+10 : c=c+10 fun_add=a+b+c End function 问题出在哪? Private sub command1_click() Dim v1 as integer,v2 as integer,v3 as integer V1=2 : v2=3 : v3=4 Debug.print v1+v2+v3*fun_add(v1,v2,v3) End sub 53

练 习 (1)写出程序运行结果(2)若改为按值传递,结果又如何? 练 习 (1)写出程序运行结果(2)若改为按值传递,结果又如何? Dim p As integer, q As integer, r As integer Private Sub Form_Click() p = 2: q = 3 Print p, q, r Call pq(p, q, r) End Sub Private Sub pq(x As integer, y As integer, z As integer) x = p + q y = p - q z = x + y 54

练 习 写程序运行的结果: Option Explicit Private Sub command1_click() 练 习 写程序运行的结果: Option Explicit Private Sub command1_click() Dim i As Integer, j As Integer Dim k As Integer i = 1: j = 2 k = fun(i, fun(i, j)) + i + j Print "I="; i; "J="; j; "K="; k End Sub Private Function fun(a As Integer, ByVal b As Integer) As Integer a = a + b b = b + a fun = a + b End Function 55

8.4.4 数组参数 VB允许把数组作为形式参数,声明数组的格式是: <数组名>() As <数据类型> [注意]: (1)数组参数只能按地址传递,即不能用ByVal来修饰数组参数 (2)定义数组参数时无须说明数组的维数和下标变化范围; (3)调用过程时,对应的实在参数也必须是数组,但只需要数组名,无须后跟括号,且数据类型也要一致。` (4)在过程体或函数体中无须对数组参数再次说明; (5)若实参是动态数组,在过程体或函数体中可以使用重定义语句修改数组的维界; 56

举例 Private Sub Form_Click() Dim a() As Integer, i As Integer Dim n As Integer n = InputBox("请输入数组的初始大小") ReDim a(n) For i = 1 To n a(i) = i Next i Call PrintArray(a) Call Array1(a) End Sub Private Sub PrintArray(x() As Integer) Dim i As Integer For i = LBound(x) To UBound(x) Print x(i); Next i Print End Sub Private Sub Array1(a() As Integer) Dim m As Integer, n As Integer n = UBound(a) m = InputBox("请输入新大小") ReDim Preserve a(m) Dim i As Integer For i = n + 1 To m a(i) = 0 Next i End Sub 输入5和8,程序执行结果为: 57

举例:自定义一个将一维数组按从小到大排序的通用过程。 Private Sub sort(a() As Integer) Dim i As Integer, j As Integer For i = 1 To UBound(a) - 1 For j = i + 1 To UBound(a) If a(i) > a(j) Then temp = a(i) a(i) = a(j) a(j) = temp End If Next j Next i End Sub Private Sub Command1_Click() Dim i As Integer, j As Integer Dim a(10) As Integer For i = 1 To 10 a(i) = Int(8 * Rnd) Picture1.Print a(i); Next i Call sort(a) Picture2.Print a(i); End Sub 58

若不希望实参随形参改变,就将参数传递方式定义为传值 练 习 完善程序:本程序的功能是找出100~200之间的所有素数。 Private Sub Form_Click() Dim i As Integer, x As Integer For i = 100 To 200 If Then Print i Next i End Sub Private Function prime( ) As Boolean Dim i As Integer For i = 2 To Sqr(n) If n Mod i = 0 Then Next i prime = True End Function 若不希望实参随形参改变,就将参数传递方式定义为传值 Prime(i) ByVal n As Integer Exit Function 59

8.4.5 对象参数 不做要求 在VB中,支持过程的形参是对象: 当传递窗体时,定义形参类型是Form; 8.4.5 对象参数 在VB中,支持过程的形参是对象: 当传递窗体时,定义形参类型是Form; 当传递控件时,定义形参类型是Control. 不做要求 60

错误的调用:fact(n)=n*fact(n-1) 8.5 递归过程 所谓递归,就是在过程定义中,调用过程本身。 例:使用递归函数求N!。 [提示]:N!=N*(N-1)! 表示为:fact(n)=n*fact(n-1) Private Sub Form_Click() Dim n As Integer n = InputBox("输入一个正整数") Print n; "!="; fact(n) End Sub 错误的调用:fact(n)=n*fact(n-1) Private Function fact(ByVal n As Integer) As Long If n = 1 Then fact = 1 Else fact = n * fact(n - 1) End If End Function 函数调用,调用自身 61

使用递归算法,最重要的是要有一个结束递归的条件,可以使递归得以返回,即终止条件或边界条件。 执行过程分析(以输入3为例): 逐层返回 逐层调用 1 Fact(3) 3*Fact(2) Fact(2) 2*Fact(1) Fact(1) 6 2 总结: 使用递归算法,最重要的是要有一个结束递归的条件,可以使递归得以返回,即终止条件或边界条件。 62

例:使用递归算法计算裴波拉挈数列。 Private Sub Form_Click() Dim n As Integer n = InputBox("求数列的第几项") Print “数列中第”; n; “项是”; Cal(n) End Sub Private Function Cal(n As Integer) If n = 1 Or n = 2 Then Cal = 1 Else Cal = Cal(n - 1) + Cal(n - 2) End If End Function 63

上例的非递归解法——例5-7(P109)。 递推法:利用未知项与已知项之间存在的某种关系,从已知项逐项推出未知项的方法。 Private Sub Form_Click() Dim fb() As Integer Dim i As Integer,, n as integer n = InputBox(“求数列中第几项的值”) Redim fb(n) fb(1)=1:fb(2)=1 For i = 3 To n fb(i)=fb(I-1)+fb(I-2) Next i Print "数列中的第"; n; "项是"; fb(n) End Sub 64

[例8-9]:编写一个递归函数,求任意两个整数的最大公约数。 P190 Private Sub Command1_Click() Dim Gcdvalue As Long, M As Long, N As Long If M < > 0 And N < > 0 Then Gcdvalue = Gcd(M, N) Text3.Text = CStr(Gcdvalue) End If End Sub Private Function Gcd(ByVal X As Long, ByVal Y As Long) Dim R As Long R = X Mod Y If R = 0 Then Gcd = Y Else X = Y :Y = R :Gcd = Gcd(X, Y) End If End Function Private Function Gcd(ByVal a As Long, ByVal b As Long) Dim r As Long r = a Mod b Do While r<>0 a=b b=r r=a Mod b Loop Gcd = b End Function 65

2、返回调用程序的调用语句,接着执行下面的语句。 练 习 请注意: 1、逐层调用, 逐层返回。 2、返回调用程序的调用语句,接着执行下面的语句。 写出下列程序运行的结果: Private Sub Command1_Click() Dim a As Integer a = 2 Call sub1(a) End Sub Private Sub sub1(x As Integer) x = x * 2 + 1 If x < 10 Then Call sub1(x) End If Print “x=”;x 66

8.6 变量的作用域 关键字 使用位置 作用域 Public 在标准模块的声明段中 全局 Private和Dim 在模块的声明段中 模块 在过程中 局部|过程 Static 局部、静态 67

8.6.1 过程级变量 例: Private Sub Command1_Click() 问: Dim i As Integer 在一个过程内部声明的变量,只在过程内部有效,又称为局部变量; 例: Private Sub Command1_Click() Dim i As Integer i = i + 1 Print i End Sub Private Sub Command2_Click() i = i - 1 问: (1)单击两次按钮1,结果是什么? (2)先单击按钮1,再单击按钮2,结果又是什么? (1) 1 1 (2) 1 -1 过程级变量,过程开始执行时,系统分配给其存储单元,而一旦过程运行结束,系统就收回存储空间。在其它过程中,不可访问。 68

8.6.2 模块级变量 Dim i As integer Private Sub Command1_Click() i = i + 1 8.6.2 模块级变量 在模块的“通用”声明段中用Private和Dim声明的变量,模块中任何一个过程都可以访问; Dim i As integer Private Sub Command1_Click() i = i + 1 Print i End Sub Private Sub Command2_Click() i = i - 1 问: (1)单击两次按钮1,结果是什么? (2)先单击按钮1,再单击按钮2,结果又是什么? (1) 1 2 (2) 1 0 模块级变量,在模块加载时,即分配给其内存存储单元,模块中任意过程均可对该变量进行操作,直到模块卸载时,系统才收回存储空间。但在其它模块中,不可访问。 69

8.6.3 全局变量 在模块的通用部分用Public声明的变量,在整个应用程序中都可访问,即在其他模块也可以访问。全局变量分为两种: 8.6.3 全局变量 在模块的通用部分用Public声明的变量,在整个应用程序中都可访问,即在其他模块也可以访问。全局变量分为两种: 第一种——在窗体模块(.frm)中定义: 窗体1中的程序代码 Public I as Integer Private Sub Command1_Click() I=I+1 End Sub Private Sub Command2_Click() Form2.Show 窗体2中的程序代码: Private Sub Form_Click() Print Form1.I End Sub 问:单击十次按钮1,再单击按钮2,单击窗体2,结果是什么? 变量I是在窗体1中的通用部分定义的公有变量,其他模块可以访问它,但必须在变量前加上所属窗体的名称。 70

Private Sub Command1_Click() I=I+1 End Sub 第二种——在标准模块(.bas)中定义: 窗体1中的程序代码 Private Sub Command1_Click() I=I+1 End Sub Private Sub Command2_Click() Form2.Show 窗体2中的程序代码: Private Sub Form_Click() Print I End Sub 标准模块1中的程序代码: Public I as Integer 变量I是在标准模块1中的通用中定义的公有变量,其他模块可以直接访问,即无须在变量前加任何修饰。 71

8.6.4 关于同名变量 当变量的作用域不同时,允许变量的名称相同。 例如: 问: (1)单击两次按钮1,再单击按钮2,结果是什么? 8.6.4 关于同名变量 当变量的作用域不同时,允许变量的名称相同。 例如: 问: (1)单击两次按钮1,再单击按钮2,结果是什么? Dim i As integer Private Sub Command1_Click() i = i + 1 Print i End Sub Private Sub Command2_Click() i = i + 10 1 2 10 说明:当变量名称相同而作用域不同时,优先访问局限性大的变量,即作用范围小的变量屏蔽作用范围大的变量。 72

举例: Option explicit Public x as integer,y as integer,z as integer Private sub form_activate() Conflict_x Debug.print “X,Y和Z是:”,x,y,z End sub Private sub form_load() X=10 : y=20 : z=35 Private sub conflict_x() Dim x as integer x=135 思考:当把X改成 form1.x后,运行结果是什么? 73

8.6.5 静态变量 在过程内的变量定义时,用Static 关键字定义的变量。 8.6.5 静态变量 在过程内的变量定义时,用Static 关键字定义的变量。 所谓静态变量,是指仅在过程第一次执行时,分配给该变量内存单元,到过程执行结束时,并不象其它局部变量一样收回存储空间,系统并不收回分配给静态变量的存储空间,其内的内容得以保留,当再次调用执行该过程时,静态变量中保留了上次运行时的数据,本次执行可直接访问。 静态变量只在过程内有效,即是局部变量。 例 Private Sub Command1_Click() Static i As integer i = i + 1 Print i End Sub 问:(1)单击两次按钮1,结果是什么? (2)如果将Static改为Dim,结果又如何? (1)1 2 (2)1 1 74

举例: Option explicit Private sub command1_click() Dim k as integer K=5 Call static-variable(k) Debug.print “第一次调用:k=”;k Debug.print “第二次调用:k=”;k End sub 说明: 因二次过程调用时,STA的初值不同,所以虽然实参一样,但运行结果不同。 Private sub static_variable(n as integer) Static sta as integer Sta=n+sta N=sta+n End sub 75

练 习 写程序运行结果: Dim a As Integer, b As Integer ‘模块级变量 练 习 写程序运行结果: Dim a As Integer, b As Integer ‘模块级变量 Private Sub Form_click() Dim x As Integer, y As Integer a = 5: b = 3 x = x + a: y = y + b Print fun1(x, y) End Sub Private Function fun1(m As Integer, n As Integer) As Integer Static k As Integer ‘静态变量 Dim a As Integer, b As Integer ‘同名的过程级变量 a = a + m b = b - n k = k + a + b fun1 = k End Function 77

8.7 程序示例 例 8-5 例 8-6 例 8-7 ★ 例 8-11 78

[例8-5] 利用级数法编程求反正弦函数值 [分析]:求解这一类累加和的题目,关键是两点:一是通项的表示,二是求解的精度,即当通项小于等于给定的误差值时,就停止累加。 [一般形式]如下两种: Do … tx=… s=s+tx n=n+1 Loop While tx>eps Do … tx=… if tx <=eps then exit do s=s+tx n=n+1 Loop 79 [形式一] [形式二]

Private Sub Command1_Click() Dim x As Single, n As Integer, eps As Single Dim s As Single, a As Single, temp As String temp = InputBox(“请输入一个绝对值小于等于1的数与允许误差:” , “求函数值” , “0, 1e - 5“ ) temp = Trim(temp) ‘调用函数,删除前后空格 n = InStr(temp, “, ” ) ’找出分隔符,的位置 x = Left(temp, n - 1) ’取X eps = Right ( temp, Len ( temp) – n ) ’取允许误差 s = x : n = 1 Do a = afun(x, n) ’调用自定义函数,求通项 If a <= eps Then Exit Do s = s + a n = n + 1 Loop Label2.Caption = "arcsin(" & CStr(x) & ")=" Text1.text = s End Sub 80

Private Function afun(ByVal x As Single, ByVal n As Integer) As Single Dim i As Integer, p As Single p = 1 For i = 1 To n p = p * (2 * i - 1) / (2 * i) Next i afun = p * x ^ (2 * n + 1) / (2 * n + 1) End Function 81

[例8-6] 改进的冒泡排序法 分析: 传统的冒泡排序法,共进行N-1轮扫描,每轮依次进行A(1)与A(2), A(2)与A(3),…直至A(10-i)与A(10-i+1)的比较,一旦前者比后者大,即交换他们的值。 如果有数据序列:1,2,3,4,5,7,6;其实它只要进行一轮扫描,即排好序;但传统的冒泡排序法,不管它已排好序,还继续进行5轮扫描,只是不交换任何元素,这其实毫无意义。 因此,在改进的冒泡排序法中,我们增设了一个开关Switch在比较过程中,若发生了数据交换,则设为True,而若一轮比较下来,没有发生数据交换,即此序列已排好序,就设为False,在每轮比较结束时,判断开关Switch的值,若为False,退出循环,结束扫描。 82

[改进的冒泡排序程序] ub=Ubound(a) Switch=True Do While swtich Switch=False For j=1 to ub ’n-I If a(j) > a(j+1) Then TEMP=A(j) : A(j)=A(j+1):A(j+1)=TEMP End If Next j Loop 83

例8-7 把一个任意十进制转换成N进制数(N<=16) E 78 4 14 16 余数 商 84

十六进制的基本元素是0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F。 二进制的基本元素是0和1 ; 八进制的基本元素是0、1、2、3、4、5、6、7 ; 十六进制的基本元素是0、1、2、3、4、5、6、7、8、9、A、B、C、D、E、F。 可以看出十六进制的基本元素包含其他两种进制的基本元素,因此,我们定义数组Char(15),依次存放最大进制——十六进制的基本元素。 以整除N的余数作为下标,取数组Char(15)中的元素就是需要的结果。 85

Dim N As integer, Num As Long Private Sub Command2_Click() End End Sub Option Explicit Dim N As integer, Num As Long Private Sub Command2_Click() End End Sub Private Sub Text1_Change() N = Val(Text1) Label4.Caption = Str$(N) + "进制数" Private Sub Text2_Change() Num = Val(Text2) N进制 需转换的数 86

调用过程trans,实参是数组,只需数组名 Private Sub Command1_Click() Dim Ch As String, i As integer Dim Char(15) As String Dim Bin() As String For i = 0 To 9 Char(i) = Str$(i) Next i For i = 0 To 5 Char(10 + i) = Chr$(Asc("A") + i) Print ReDim Bin(1) Call trans(Bin, Char) For i = UBound(Bin) To 1 Step –1 Ch = Ch + Bin(i) Text3 = Ch End Sub 数组 Char 元素0 1 2 …9 A B C D E F 下标0 1 2…..9 10 11 12 13 14 15 调用过程trans,实参是数组,只需数组名 逆序输出结果数组Bin元素 87

Private Sub trans(vary() As String, st() As String) Dim R As integer Bin Char Private Sub trans(vary() As String, st() As String) Dim R As integer Dim K As integer K = 0 Do Until Num = 0 R = Num Mod N K = K + 1 ReDim Preserve vary(K) vary(K) = st(R) Num = int(Num / N) Loop End Sub 结束条件商为0 不断增加动态数组上界,以存放新元素 注意语句 的次序 以余数为下标,找出数组中对应的字符 如:14“E” 或Num \N 将余数依次存放在动态数组vary中 88

[例8-11]:直接插入排序法——从小到大的顺序。 将待排序的N个数据存放在数组SORT中,首先将SORT(1)认为已排序子序列,然后依次将SORT(2)、 SORT(3)、… SORT(N)插入到已排好序的子数列中。每插入一个元素都依次进行以下三个操作。 1.先将待插元素SORT(I)放入变量Temp中; 2.寻找插入位置:将temp依次与SORT(I-1)、 SORT(I-2)、… 进行比较,一旦SORT(k)< temp,则停止比较,插入位置即是SORT(K)之后; 3.空出位置,将元素插入:将SORT(k+1) 至SORT(I-1)的元素依次后移一位,再将变量temp的值放入SORT(K+1)中;注意:为避免元素值丢失,必须先将SORT(I-1)赋给SORT(I), SORT(I-2)赋给 SORT(I-1),…,直至 SORT(K+1)赋给 SORT(K +2 ). … … 重复上述操作,将每个元素都插入到指定位置中。 89

直接排序示例 排序前 3 6 1 5 4 2 1 3 2 3 6 3 6 5 4 4 6 5 5 6 6 排序后 Temp 6 1 5 4 2 90

寻找第一个比temp小的元素的位置 取待排序的元素 一边比较 一边后移 K指向前一个元素 为temp的插入位置 Private Sub insertion(sort( ) As Integer) Dim k As Integer, i As Integer, temp As Integer,Ub As Integer Ub = UBound(sort) For i = 2 To Ub temp = sort (i) k = i - 1 Do While temp < sort(k) sort(k + 1) = sort(k) k = k - 1 If k <= 0 Then Exit Do Loop sort (k + 1) = temp Next i End Sub 寻找第一个比temp小的元素的位置 取待排序的元素 一边比较 一边后移 K指向前一个元素 temp比已排序的所有元素都小则结束 为temp的插入位置 91