第 4章 数组与 自定义 类型
4.1 数组的概念
4.2 数组的基本操作
4.3 控件数组
4.4 自定义类型
4.5 枚举类型
4.6 常用算法举例
4.1 数组的概念
数组是 一组相同类型数据 的集合。可用 数组名 代表这一批数。
组成数组的每 个数据都是该数组的 元素,用 数组名(下标) 来表示。例:
Dim a(1 to 10) as integer ’定义 a是下标为 1至 10的 一维 整型 数组
a(1) a(2) a(3) a(4) a(5) a(6) a(7) a(8) a(9) a(10)
dim b(10) as integer ’若省略下标上界,则默认为 0,b(0)~b(10)
dim c(1 to 3,1to 4) as integer c(1,1) c(1,2) c(1,3) c(1,4)
c(2,1) c(2,2) c(2,3) c(2,4)
c(3,1) c(3,2) c(3,3) c(3,4)
Dim d(2,3) as string ’d为 3× 4的二维数组,元素为 d(0,0)~ d(2,3)
Dim e() as single ’e为动态数组,维数和下标范围都没确定
C为 3× 4的二维数组数组分类
Visual Basic中的数组,按不同的方式可分为以下几类,
按数组的大小 ( 元素个数 ) 是否可以改变来分为:定长数组,动态 ( 可变长 ) 数组 。
按元素的数据类型可分为:数值型数组,字符串数组,日期型数组,变体数组等 。
按数组的维数可分为:一维数组,二维数组,
多维数组 。
对象数组:菜单对象数组,控件数组 。
数组的声明?格式为:
Dim arrayname([subscriptrange[,subscriptrange… ]])[As type]
arrayname是数组的名字 。 是一个标识符,命名规则与普通变量相同 。
subscriptrange指定数组中元素的下标范围,它出现的次数则代表了数组的维数 。
type指定 arrayname的数据类型 。
As type子句是可选的,用来说明数组的类型,如果缺省,则与变量的声明一样,默认为是变体类型数组 。
Dim语句用于数组声明的简单形式完成四个任务:
① 建立数组名 。
② 建立数组的数据类型 。
③ 指定数组中元素的数目 。
④ 初始化数组中每个元素的值 。 数值数组元素成为 0,字符串数组元素为空字符串,Variant数组元素的值为特别值 Empty。
4.1.2 静态数组和动态数组
1,静态数组在声明时确定了大小的数组称为静态数组
(1) 一维数组的声明 (无隐式声明 )
形式,
Dim 数组名 ([<下界 >to]<上界 >)[As <数据类型 >]
或,Dim 数组名 [<数据类型符 >]([<下界 >to]<上界 >)
例,Dim a(1 to10) As Integer ’声明 a数组有 10个元素 a(1)~a(10)
若 <下界 >缺省,则为 0 例,Dim b(10) As Integer
声明了 b数组可有 11个元素 b(0)~b(10)
1是下标的下界 10是下标的上界 数组元素的数据类型说明:
1,数组名的命名规则与变量的命名相同 。
2,数组的元素个数,上界 -下界 +1。
3,缺省 <下界 >为 0,若希望下标从 1开始,可在模块的通用部分使用 Option Base语句将设为 1。 其使用格式是:
Option Base 0|1 ' 后面的参数只能取 0或 1
例如:
Option Base 1 ' 将数组声明中缺省 <下界 >下标设为 1
4,<下界 >和 <上界 >不能使用变量,必须是常量,常量可以是直接常量、符号常量,一般是整型常量。
5,如果省略 As子句,则数组的类型为变体类型 。
6,数组中各元素在内存占一片连续的存储空间,一维数组在内存中存放的顺序是下标大小的顺序,如图 4-1所示:
图 4-1 数组中各元素的存储顺序使用形式,数组名 (下标 )
其中:下标可以是整型变量,常量或表达式 。
例如,设有下面的数组 B(10) As Integer
则下面的语句都是正确的 。
A(1)=A(2)+B(1)+5 ' 取数组元素运算
A(i)=B(i) ' 下标使用变量
B(i+1)=A(i+2) ' 下标使用表达式引用不能下标越界。
(2)一维数组 元素 的引用
(2) 多维数组多维数组的声明声明格式如下:
Dim 数组名 (下标 1,下标 2[,下标 3… ]) [As 数组类型 ]
功能:声明一个二维数组或多维数组并分配相应的存储单元 。
说明,参数与一维数组完全相同 。 下标的个数决定了数组的维数,多维数组最大维数为 60。 每一维的大小为:上界-下界+ 1;
数组的大小为每一维大小的乘积 ( 所谓数组的大小是指数组元素的总个数 ) 。
例如,Dim a(0 to 2,0 to 3) As Single
二维数组在内存的存放顺序是,先行后列,。 例如数组 a的各元素在内存中的存放顺序是:
a(0,0)→a(0,1)→a(0,2)→a(0,3)→a(1,0)→a(1,1)→a(1,2)→
a(1,3)→a(2,0)→(2,1)→a(2,2)→a(2,3)
多维数组的引用引用形式,数组名 (下标 1,下标 2,下标 3… )
例如,a(1,2)=10
a(i+2,j)= a(2,3)*2
在程序中常常通过多重循环来操作使用多维数组元素 。
⑶ Option Base语句格式,Option Base n
功能:改变数组下标的缺省下界 。
说明,n为数组下标的下界,只能是 0或 1。
该语句在程序中只能使用一次,且必须放在数组声明语句之前 。
特别注意:声明静态数组时,下标范围不能用变量名表示 ( 即使变量已赋值也不行 ) 。
2,动态数组
动态数组可以在任何时候改变大小。
⑴ 创建动态数组步骤为:
① 给数组附以一个空维数表,这样就将数组声明为动态数组 。
格式:
Dim/Private/Public/Static 数组名 ( ) [As 数组类型 ]
例,Dim DynArray( )
② 用 ReDim语句分配实际的元素个数 。
格式,ReDim 数组名 (下标 1,下标 2[,下标 3… ])
例:
ReDim DynArray(4 to 12) '将动态数组 DynArray的下标范围确定下来 ( 从 4到 12)
特别提示:用 ReDim语句重新定义数组时,可用变量名指定数组下标范围;而用 Dim语句定义静态数组时,则不能用变量名来指定下标范围 。
⑵ 保留动态数组的内容
每次执行 ReDim语句时,当前存储在数组中的值都会全部丢失。 Visual Basic重新将数组元素的值置为
Empty(对 Variant数组)、置为 0(对 Numeric数组)、
置为 零长度字符串 (对 String数组)或者置为 Nothing
(对于对象型数组)。
若希望改变数组大小又不丢失数组中原来的已有数据。
使用具有 Preserve关键字的 ReDim语句就可做到这点。
ReDim Preserve DynArray(UBound(DynArray)+1)
在用 Preserve关键字时,只能改变多维数组中最后一维的上界;如果改变了其它维或最后一维的下界,那么运行时就会出错。
例如:
3,获得数组上、下界
求得数组的上界与下界的两个函数
UBound(Arrayname[,Dimension])
LBound(Arrayname[,Dimension])
其中,Arrayname表示数组的名字,如果 Arrayname所代表的是多维数组,Dimension参数可用来指定,哪一维的上 ( 下 ) 界,,例如:
Dim a(5) As string
Dim n1 As Integer,n2 As Integer
n1=LBound(a) ' n1=0
n2=UBound(a) ' n2=5
dim b(1 to 5,0 to 3) as integer
print Lbound(b,1) ' 1
print Ubound(b,2) ' 3
4.2.2 数组的输入、输出和复制
1.数组的输入
⑴ 对少数个别元素赋值,可采用赋值语句。
如,Dim A(10) AsInteger
A(1)=3,A(4)) =7
⑵ 如果要给数组中的所有元素都赋值,可用循环实现。
例如:
Dim S(1 To 2,1 To 3)
For i = 1 To 2
For j = 1 To 3
S(i,j) = InputBox("请 输入 1个数 ")
Next j
Next i
数组元素可当作普通变量使用
⑶ 对于较大的数组,一般不用 InputBox函数,而用 Array函数为数组元素赋值。
格式:
数组变量名 =Array(数据 1,数据 2,… )
功能:把一组数据赋给一个数组 。
说明:
① 利用 Array()函数对数组每个元素赋值时,声明的数组应为 可变数组 ( 甚至声明时 连圆括号都可省略 ),并且其类型只能是 Variant。
② 所需的 "数据 "参数是一个用逗号隔开的常数值表,这些值用于给 Variant所包含的数组的各元素赋值 。
例如,Dim AAs Variant
A=Array(10,20,30) '则,A(0)=10,A(1)=20,A(2)=30
③ 使用 Array()函数创建的数组的下界默认为 0,或是由
Option Base语句指定的下界;上界由 Array()函数括号内的参数个数决定,如果不提供参数,则创建一个长度为 0的数组。
2,数组的输出数组元素的输出可以使用循环和 Print语句来实现。
例 1 输出如下图所示的下三角数据。
Dim sc(5,5) As Integer,i%,j%
For i = 1 To 5
For j = 1 To i
sc(i,j) = i * 5 + j
Print sc(i,j); " ";
Next j
Print ' 换行
Next I
3,数组的复制可通过循环对数组各元素一一复制,还可以:
VB6.0支持用变量名赋值语句实现两个数组复制。
Dim a(4) As Integer,b( ) As Integer
a(0)=0,a(1)=6,a(2)=12,a(3)=18,a(4)=24
b=a ' 将数组 a的各元素的值赋给 b
在该程序段中,b=a语句相当于执行了:
ReDim b(UBound(a))
For i=0 to UBound(a)
b(i)=a(i)
Next i
注意:
赋值号两边的数据类型必须一致 。
如果赋值号左边是一个动态数组,则复制时系统自动将动态数组 ReDim成右边同样大小的数组 。
如果赋值号左边的是一个大小固定的静态数组,则复制时出错 。
4.2.3 FOR EACH…NEXT 语句
For Each...Next 循环的语法如下:
For Each element In group
statements
Next element
使用 For Each...Next时的几点限制:
若 group 是普通数组名,则 element只能是 Variant变量;
若 group 是控件数组名,则 element须是控件变量;
For Each...Next不能用于后面将介绍的自定义类型数组。
注意:
For Each...Next 循环与 For...Next 循环类似,但它对数组或对象集合中的每一个元素重复循环体语句。
例:利用输出字符数组 a中每个元素
4.3 控件数组
1 控件数组的概念一组相同类型控件组成的集合。 它们共用一个控件名,
具有相同的属性,建立时系统给每个元素赋一个唯一的下标。
控件数组例 1
控件数组各元素共享同样的事件过程,通过下标参数值区分控件数组中的各个元素。
例,Private Sub cmdName _Click( Index As Integer )

If Index=3 then
' 处理第四个命令按钮的操作
End If

End Sub
控件数组例 2
2 控件数组的建立
(1) 在设计时建立控件数组的步骤:
① 窗体上画出控件,设置属性,就建立了第一个元素;
② 选中该控件,执行,复制,操作,再执行,粘贴,若干次,就建立了所需个数的控件数组元素 。
③ 进行事件过程的编程 。
(2) 在运行时动态添加控件数组的方法,
① 在设计时画出一个母体控件,并设置该控件的 Index值为
0,表示该控件为数组,这是建立的第一个元素。
② 在代码中运用 Load方法,添加其余的若干个元素;也可以运用 Unload方法,删除某个添加的元素。
Load方法和 Unload方法的使用格式:
Load 控件数组名 (下标 )
Unload 控件数组名 (下标 )
其中,下标 为整型数据,指明是控件数组的哪个元素 。
③ 通过 Left和 Top属性确定每个新添加的控件数组元素在窗体中的位置,并将 Visible 属性设置为 True。
例如,设计时已经有控件 Label(0),可以写语句:
Load Label(1)
Label(1).Left=Label(0).Left
Label(1).Top= Label(0),Top+ Label(0),Height
Label(1).Visible=True
例 4-3 运行时添加和删除控件。
在这个示例中,用户可以通过单击按钮来添加(和删除)
单选钮 ;通过选择单选钮来改变图片框背景颜色。如图 4-
4所示。
图 4-4 例 4-3程序界面例 4-4 在控件数组中使用 FOR EACH… NEXT语句 。 在窗体上 建 立 若干 文 本框 组 成的 控 件数 组,然 后使 用 For
Each...Next 语句搜寻文本框数组中所有成员,并查看其 Text
属性,看是否有 Text内容等于,Hello”的字符串 。 若找到了显示,True”;未找到显示,False”。
程序中,使用控件类型的变量 MyObject。 注意,定义控件类型的变量所用关键字为 Control。 设置逻辑变量 Found作为是否找到,Hello”字符串的标志变量 。 程序运行界面如下:
例 4-4程序运行界面
4.4 自定义类型
1,自定义数据 类型的定义基本 ( 标准 ) 类型数据类型构造 ( 自定义 ) 类型
Type 语句 的语法如下,
[Private∣ Public] Type 类型名成员变量名 1[(下标 )] As xxx
成员变量名 2 [(下标 )] As xxx
… …
End Type
各参数的含义如下:
类型名,自定义类型名,
取名规则和一般标识符相同。
成员变量名,或称元素名,表示自定义类型中的一个成员。
下标,有下标表示该成员是数组。
xxx:类型名,为标准数据类型的关键字。
2,自定义类型 变量的声明 和使用
定义自定义类型的变量可以使用下面的语句,
Dim 变量名 As 类型名
访问自定义类型变量的形式如下:
变量名,元素名 ( 每次只能访问该变量的一个元素 )
可 定义 自定义类型的数组,格式为:
Dim 数组名 (下标范围 ) As 类型名例 4-5 使用自定义类型的数组。
4.5 枚举类型
什么是枚举类型
使用 枚举类型的目的是提高程序描述问题的直观性
定义格式:
Private/Public Enum MyEnum
Enumname1 ’第一个枚举值,对应常数 0
Enumname2 ’第一个枚举值,对应常数 1



Enumnamen ’第一个枚举值,对应常数 n-1
End Enum
用于定义枚举类型的关键字自定义的类型名

Public enum weekday
sun
mon
tue
wed
thu
fri
sat
End Enum
dim day as weekday
day=sat
if((day=sat)or(day=sun)) then
MsgBox,Lets take a holiday
End if
If day<sat)and(day>sun))
MsgBox,Lets work”
End if
4.6 常用算法举例
4.6.1 分类统计将一批数据中按分类的条件统计包含的个数例 4-6 输入一串字符,统计各字母出现的次数,大小写字母不区分。
【 分析 】 显然,对字母分类,共有 26类,统计每类字母的出现次数需 26个计数变量 。
(1) 26个计数变量分别用来统计 26个字母各出现的次数,
可以用具有 26个元素的数组实现比较方便,每个元素的下标表示对应的字母,元素的值表示对应字母出现的次数 。
(2) 从输入的字符串中逐一取出字符,统一转换成大写字符判断 ( 使得大小写不区分 ) 。
(3) 界面设计,可以用一个文本框接收输入的一串字符,而统计结果打印在图片框上。
4.6.2 数组排序
1.选择法排序算法思想 ( 以升序排序为例 ),
1) 对有 n个数的序列 ( 存放在数组 a(n)中 ),从中选出最小的数,与第 1个数交换位置;
2) 除第 1 个数外,其余 n-1个数中选最小的数,与第 2
个数交换位置;
3) 依次类推,选择了 n-1次后,这个数列已按升序排列 。
按 升序(从小到大) 排序的算法流程图 (p用来记录某趟交换中最小数的下标)
关键代码如下:
For i = 1 To n - 1
p = i
For j = i + 1 To n
If a(j)< a(p) Then p = j
Next j
temp = a(i)
a(i) = a(p)
a(p) = temp
Next i
例 4-7 (从小到大升序) 选择法 排序的 VB程序 。
a(i)与 a(p)交换值
2,冒泡法排序 ( 以升序为例 )
算法思想,(将相邻两个数比较,小的调到前头 )
1) 有 n个数 ( 存放在数组 a(n)中 ),第一趟将每相邻两个数比较,小的调到前头,经 n-1次两两相邻比较后,最大的数已,沉底,,放在最后一个位置,小数上升,浮起,;
2) 第二趟对余下的 n-1个数 ( 最大的数已,沉底,) 按上法比较,经 n-2次两两相邻比较后得次大的数,沉底,;
3) 依次类推,n个数共进行 n-1趟比较,在第 j
趟中要进行 n-j次两两比较 。
冒泡法按 升序(从小到大) 排序的算法流程图如下:
关键代码如下:
For i = 1 To n - 1
For j = 1 To 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
Next i
例 4-8 对已知存放在数组中的 n个数,用冒泡法按递增顺序排序。
例 4-8 冒泡法按递增顺序排序
一次输入多个数据示例
– 可使用附录 2,第 311页的 split函数
补例 1:输入 10个数,统计其中正数,0、
负数的个数分别是多少。
补例 2:打印如下杨辉三角前 10行
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
…………
4.6.3 数组元素的查找、插入与删除
1,查找数组中的元素例 4-9 利用顺序查找法查找考场教室号
【 分析 】
(1) 为便于查找,通过二维数组 rm建立这两种号码对照表。
(2) 创建应用程序的用户界面和设置对象属性 。
(3) 编写程序代码。
功能要求:用户在文本框 Text1中输入准考证号码,
单击,查找,按钮 (Command1)后,则查找出对应的教室,并将教室号码输出在文本框 Text2中。
例 4-10 * 采用折半查找法查询学生成绩。
【 分析 】
折半查找法也称对半查找法,是一种效率较高的查找方法。
对于大型数组,它的查找速度比顺序查找法快得多。
在采用折半查找法之前,要求将数组按查找关键字 (如本例的学号 )排好序 (从大到小或从小到大 )。
折半查找法的过程描述如下:
先从数组中间开始比较,判别中间的那个元素是不是要找的数据:
是,则查找成功。
否,若被查找的数据是在该数组的上半部,则从上半部的中间继续查找;否则从下半部的中间继续查找。
照此进行下去,不断缩小查找范围。
至最后,因找到或找不到而停止查找。
2,数组元素的插入与删除在数组中首先找到要插入的位置,然后进行插入 。
(1) 插入元素例 4-11 在有序数组 a(1 To n-1)(原有 n-1个元素 )
插入一个值为 Key的元素 。
【 分析 】
① 查找要插入的位置 k( 1<= k <= n-1) ;
② 腾出位置,从最后一个元素开始到第 k个元素,
逐个往后移动一个位置;
③ 第 k个元素的位置腾出,就可将数据 Key插入 。
(2) 删除元素删除操作首先也是要找到欲删除的元素的位置 k;
然后从第 k+1到第 n个位置开始向前移动;最后将数组元素个数减 1。
例 4-12 在数组 a(1 to n)删除一个值为 Key元素 。
【 分析 】
① 查找要删除的位置 k( 1<= k <=n) ;
② 从 k+1位置开始,到最后一个元素每个元素往前移动一个位置;
③ 数组长度减 1;
④ 要将数组长度减 1,须将数组声明为动态数组 。
实验
实验四 基本操作题 1,2
输入 10个数,求它们的平均数并将它们按与输入相反的顺序输出( 用与题 1不同的方法 )
输出 Fibonacci数列前 20项(不用数组和用数组两种方法) 1,1,2,3,5,8,13…..
选作题:综合应用题 4
请上机前把程序写好