第5章数组与自定义类型在程序中处理数据时,对于输入的数据、参加运算的数据、运行结果等临时数据,通常使用变量来保存,由于变量在一个时刻只能存放一个值,因此当数据不太多时,使用简单变量即可解决问题。但是,有些复杂问题,利用简单变量进行处理很不方便,甚至是不可能的。例如以下几个问题。(1)输入50个数,按逆序打印出来。(2)输入100名学生某门课程的成绩,要求把高于平均分的那些成绩打印出来。(3)统计高考中各分数段的人数。(4)某公司有近万名职工,要求做一个职工工资报表。(5)窗体上的几个同类型控件,有着某种关系。这就需要我们构造新的数据结构——数组。
5.1数组的概念数组是具有相同类型的有序变量的集合,可用于存储成组的有序数据。根据数组的定义,我们必须明确以下几点。(1)数组的命名与简单变量的命名规则相同。(2)数组中的元素是有序排列的。(3)数组的元素个数是有限的,数学中的无限数组不能表示。(4)数组的类型也就是该数组的下标变量的数据类型。在Visual
Basic中,可以说明任何基本数据类型的数组(包括用户自定义类型),但是一个数组中的所有元素应该具有相同的数据类型,只有当数组的数据类型为Variant时,各个元素的数据类型可以不同。
5.1.1数组的声明 1.数组的声明数组必须先声明后使用,声明的格式如下。 Dim | Private | Public |
static 数组名(维数说明)[As
类型]对数组进行声明应该包括数组名、维数、大小、类型及作用域。数组的命名规则和变量的命名规则一致。
Dim:用于在过程(Procedure)、窗体模块(Form)或标准模块(Module)中声明数组变量。在过程中使用Dim时,所声明的数组变量的作用域为过程级(作用范围为数组声明所在过程)、在窗体模块或标准模块的通用声明段中使用Dim时,所声明的数组变量的作用域为模块级(作用范围为数组声明所在模块)。
Private:用于在窗体模块、标准模块的通用声明段中声明一个模块级的私有数组变量,其作用域为模块级。在窗体模块或标准模块的通用声明段使用Private和使用Dim的作用效果相同。
Public:用于在标准模块中声明公用数组变量,所声明的数组变量的作用域为整个应用程序。在Visual
Basic中,允许在窗体模块中使用Public声明公用简单变量,但是不允许在窗体模块中使用Public声明公用数组变量。
Static:用于在过程中声明静态数组变量,所声明的静态数组变量的作用域为该过程。
2.数组元素和下标数组声明后,仅仅表示在内存中分配了一段连续的存储空间。对数组进行操作,一般是针对某个元素进行操作。数组元素是带有下标的变量,是数组的一个成员,其一般形式如下。数组名(下标1
[,下标2,……])如:A(2)B(2+2,1)C(1*2,3,1)D(i)下标表示顺序号,每个数组元素有唯一的顺序号。下标可以是常数、数值变量、算术表达式,甚至可以是一个数组元素。下标中如果含有变量,使用前该变量应提前赋值。多个下标之间应该由逗号分隔。下标值应该为整数,否则计算机将对下标自动取整。比如a(3.2)将被视为a(3),a(-3.7)将被视为a(-4)。
3.数组的维数和维界标志一个数组元素所需的下标个数称为数组的维数。所以有一维数组、二维数组及两个以上下标的多维数组。在Visual
Basic中,理论上数组的维数最多可以达到60维。下标的取值范围称为数组在这一维的界。在Visual
Basic中,维界不得超过Long数据类型的范围(-2 147 483 648~2 147 483
647)。我们把下标所取的最大值称为上界,最小值称为下界(默认为0)。数组的下标在上下界内是连续的。对某一维数组元素而言,其下标不能超出维界的范围,否则会出现“下标越界”的错误。在数组声明语句的维数说明中,如果明确指出维界,则声明的是固定大小数组;否则,声明的是动态数组。
4.数组的数据类型和大小数组的数据类型由数组声明语句中的As
类型决定,可以是整型、长整型、单精度型、双精度型、货币型、字节型、字符串型、逻辑型、日期型、对象型。如果声明时省略As类型,则数组的数据类型默认为Variant类型。数组中元素的个数称为数组的大小,数组的大小与它的数据类型无关。数组的大小为每一维大小的乘积,而某一维的大小为:下界-上界+1。
5.数组的引用数组的引用通常是指对数组元素的引用。引用数组元素时,数组名、数据类型和维数必须和定义的一致。另外还要注意区分数组的声明和数组元素。例如,对于下面的程序片段:
Dim x(8)As Integer Dim Temp As Integer …
Temp=x(8)尽管有两个x(8),但是Dim语句中的x(8)不是数组元素,而是说明由它声明的数组x的下标最大值为8;而赋值语句“Temp=x(8)”中的x(8)是一个数组元素。
6.数组和简单变量的比较(1)输入的简单变量越多,程序就越长,程序本身占用的内存空间就越大。(2)在一个程序中使用的简单变量的个数有限。对大批量数据,简单变量就不能表示了。(3)简单变量的存储位置呈松散状态,数组却占据着一片连续的存储区域。(4)在程序结构方面,简单变量不适合使用循环的办法来解决。总之,简单变量适合于处理一个或几个变量的情况,每个简单变量只能存储一个数据,各简单变量之间没有固定的联系。而数组反映的是大批数据间的顺序和联系,体现的是数据间更复杂的结构,因此数组适用于处理大批量数据之间的比较、排序和检索。
7.数组的分类(1)根据数组的数据类型分为整型、长整型、单精度型、双精度型、货币型、字节型、字符串型、逻辑型、日期型、对象型(也可叫控件数组)和变体(Variant)数组等11类。(2)根据数组的作用域可分为公用数组、模块数组和局部数组三类。(3)根据数组的生命期和存放方式可分为静态数组和自动数组两类。(4)根据数组的元素个数是否变化分为固定数组和动态数组两类。
5.1.2静态数组及声明固定大小数组在声明阶段其大小就已经确定,在程序运行期间其元素个数不能改变,这种形式的数组在编译阶段就已经确定了存储空间。
1.数组的声明 1)声明格式 Dim | Private | Public | static 数组名(维界定义)[As 类型]
2)功能声明一个数组,并初始化所有数组元素。 3)说明(1)数组的维界定义必须为常数或常量符号,不能是表达式或变量。例如: Const
k As integer=10 Dim x(10)As Single''正确 Dim a(k)As long''正确 而 n=10 Dim
x(n)As Single''错误 (2)维界定义的形式是:[下界1 To ]上界1[,[下界2 To
]上界2]……一般情况下,当[下界
To]缺省时,默认值为0,下界≤上界。维的大小为:上界-下界+1。维界说明如果不是整数,将自动进行四舍五入处理。例如: Dim
sum(10)As Integer''声明sum为一维数组,共有11个元素,下标从0到10 Dim res(1 To 20)As
Single''声明res为一维数组,共有20个元素,下标从1到20 Dim x(9,19)As
Integer''声明x为二维数组,共有10*20=200个元素 Dim y(-5 To 4,9)As
Integer''声明y为二维数组,共有10*10=100个元素 Dim z(9,1 To 10,9)As
Integer''声明z为三维数组,共有10*10*10=1 000个元素 (3)As
数据类型:用来说明数组元素的类型,如果缺省,则默认为是变体型(Variant)。例如: Dim a(12)As
Single''声明a数组为单精度型 Dim x(1 To 50)As Integer''声明x数组为整型 Dim y(-9 To
10)''声明y为变体型数组 (4)声明数组时可以通过Option Base n语句来指定缺省下界,n的值只能为0或1。例如:
Option Base 1''指明缺省下界为1 Dim cup(4,5)As
Integer''声明cup为二维数组,共有(4-1+1)*(5-1+1)=20个元素 Dim da(7,1 To 10)As
Integer''声明da为二维数组,共有(7-3+1)*(10-1+1)=50个元素 注意: Option
Base语句只能在模块级使用,即在窗体模块或标准模块的通用声明段使用,而不能在过程中使用;当在某一模块中使用了Option
Base语句改变了缺省的下界值,这一缺省值只能影响到包含该Option
Base语句的模块,而其他模块中所定义的数组的下界缺省值不会受到影响。如在窗体Form1的通用声明段中加入语句Option Base
1,则只在Form1中定义数组时,默认下界值为1。(5)数组声明语句声明一个数组,将同时对所有数组元素进行初始化,把数值数组中的全部数组元素都初始化为0,把变体字符串数组中的数组元素初始化为空字符串,把定长字符串数组的元素初始化为给定长度的空格,把逻辑型数组元素初始化为False,变体型数组元素初始化为Empty。(6)声明数组也可以使用类型说明符代替As类型。例如:
Dim a$(10)''字符串类型数组 Dim b%(2,3)''整型数组 Dim
c!(3,4,5)''单精度浮点类型数组(7)声明数组时,一条声明语句可以同时声明多个相同或不同数据类型的数组。例如: Dim
a1(10)As Single,a2(10,10)As Long,a3(10,10,10)As Integer Dim
b1%(10),b2%(20),b3!(2,2),b4#(3,4,5) 4)声明数组的方法(1)建立公用数组在模块的通用声明段用
Public 语句声明数组。例如: Public Counters(14)As
Double''定义Counters为15个元素的公用数组 (2)建立模块级数组在模块的通用声明段用 Private
或Dim语句声明数组。例如: Private Sums(1 To 20)As Double''定义Sums为20个元素的模块级数组
Dim a(4)as Integer''声明模块级数组 Private Sub Command1_Click() … End Sub
(3)建立局部数组在过程中用 Dim或Static 语句声明数组。例如: Private Sub Form_Click() Dim
Subs(20)As Double''定义Subs 为20个元素的局部数组 End Sub Private Sub
Form_Click() Static s(3)As Integer End sub
2.固定大小数组使用举例【例5.1】求一个给定的一维数组中的最大元素和最小元素,并给出相应元素的下标,同时求出各元素的和及平均值。
1)控件及属性控件及属性如表5.1所示。表5.1控件及属性 控件名称(Name)属性标签Label1Caption=“最大元素”
标签Label2Caption=“最小元素” 标签Label3Caption=“各元素的和” 标签Label4Caption=“
数组元素的平均值” 标签Label5Caption=“对应下标” 标签Label6Caption=“对应下标”
文本框Text1Locked=True 文本框Text2Locked=True 文本框Text3Locked=True
文本框Text4Locked=True 文本框Text5Locked=True 文本框Text6Locked=True
按钮Command1Caption=“计算” 2)布局界面布局如图5.1所示。 图5.1界面布局 3)代码 ''变量声明 Dim b(1
To 10)As Integer Dim bmax%,bmin%,bsum%,baverage! ''计算按钮代码 Private
Sub Command1_Click() Dim imax%,imin% For i=1 To 10 If bmin
b(i)Then bmin=b(i) imin=i End If If bmax b(i)Then bmax=b(i)
imax=i End If bsum=bsum+b(i) Next i baverage=bsum 10
Text1.Text=bmax Text2.Text=bmin Text3.Text=bsum Text4.Text=baverage
Text5.Text=imax Text6.Text=imin End Sub ''窗体载入代码 Private Sub
Form_Load() Text1.Text="":Text2.Text="" Text3.Text="":Text4.Text=""
Text5.Text="":Text6.Text=""
b(1)=10:b(2)=40:b(3)=-10:b(4)=100:b(5)=1200
b(6)=-93:b(7)=-239:b(8)=76:b(9)=-921:b(10)=44 bmax=bmin=b(1)
bsum=baverage=0 End Sub
4)运行结果运行结果如图5.2所示。图5.2运行结果【例5.2】一个二维表格就是一个二维数组。数学上形如矩阵{aij}表示的数据均可用二维数组来处理。请编程完成两个相同阶数的矩阵A和B相加,将结果存入矩阵C,即C=A+B。由于阶数相同,因此只要分别求出cij=aij+bij即可。(此例为二维数组举例)
1)控件及属性控件及属性如表5.2所示。表5.2控件及属性 控件名称(Name)属性标签Label1Caption=“矩阵A”
标签Label2Caption=“矩阵B” 标签Label3Caption=“矩阵C” 图片框Picture1 图片框Picture2
图片框Picture3 按钮Command1Caption=“矩阵求和” 2)布局界面布局如图5.3所示。 图5.3界面布局 3)代码
''矩阵求和按钮代码 Private Sub Command1_Click() Picture1.Cls Picture2.Cls
Picture3.Cls Dim a(4,5)As Integer Dim b(4,5)As Integer Dim c(4,5)As
Integer For i=0 To 4 For j=0 To 5 a(i,j)=Int(Rnd * 91)+10
b(i,j)=Int(Rnd * 91)+10 c(i,j)=a(i,j)+b(i,j) Next j Next i For i=0
To 4 For j=0 To 5 Picture1.Print Format(a(i,j),"!@@@@");
Picture2.Print Format(b(i,j),"!@@@@"); Picture3.Print
Format(c(i,j),"!@@@@"); Next j Picture1.Print Picture2.Print
Picture3.Print Next i End Sub 4)运行结果运行结果如图5.4所示。 图5.4运行结果
5.1.3动态数组及声明与固定大小数组对应的是动态数组,即数组元素的个数不定且可以根据需要动态改变数组元素个数的数组。使用数组解决实际问题时,有时候可能不知道数组到底多大才合适,太大的话会占用大量的存储空间,而太小的话可能不能满足需要;或者由于程序运行的需要,要求数组的大小能够动态地变化,这时就要使用动态数组。在Visual
Basic中,动态数组很灵活,可以在任何时候改变大小,有助于有效管理内存。例如,当要处理的数据量很大时,可短时间使用一个大数组(分配比较大的存储空间),然后当数据量变小时,将原来的大数组变为一个较小的数组,从而释放部分存储空间;当不使用这个数组时甚至可以将数组所占用的存储空间全部释放。
1.动态数组的创建
1)创建方法要创建动态数组,需要分两步进行。(1)与前面的静态数组的声明类似,只是不说明维数和界限,并且不分配内存。(2)实际使用时,用ReDim语句分配实际的内存空间,格式为:
Redim [preserve ] 数组名(维界定义1 [,维界定义2 ……])[As
类型]例如,可先在模块级声明中建立动态数组DynArray。 Dim DynArray()As Integer
然后,在过程中给数组分配空间。 Sub TestArray() … ReDim DynArray(9,1 to 20) … End
Sub
2)说明(1)ReDim语句中的维界定义中的上下界可以是常量,也可以是有了确定值的变量。(2)ReDim语句只能出现在过程体内,为数组临时分配存储空间,当所在过程结束时,分配的存储空间就会释放。在过程中可以多次使用ReDim语句来改变数组的大小。(3)使用Redim语句时,如果不使用Preserve选项,则原来数组中的值丢失,即数组中的内容全部被重新初始化。(4)使用Redim语句时,如果使用Preserve选项,则对数组重新说明时,将会保留数组中原来的数据。但是不能改变维数,并且只能改变最后一维的大小,前面维的大小不能改变。例如:
Dim exa()As Integer Private Sub Form_Click() ReDim exa(2,2)''正确,二维数组
ReDim Preserve exa(2,4)''正确,保留数组原来的数据,只可改变最后一维大小 ReDim Preserve
exa(4,2)''下标越界错误,使用Preserve选项只可改变最后一维大小 ReDim Preserve
exa(2,2,4)''下标越界错误,使用Preserve选项不能改变维数 … End Sub
(5)使用ReDim语句时,可以省略As类型,即维持数组原来的数据类型。但如果使用As类型,其中的“类型”应该和此数组最初的数据类型一致,即使用ReDim语句不可以改变数组的数据类型。例如:
Dim exa()As Integer''整型 Private Sub Form_Click() ReDim
exa(2,2)''正确,省略As类型,表示整型 ReDim exa(2,4)As Integer''正确,整型,与初始定义一致
ReDim exa(2,2,2)As Single''错误,不能改变数组元素的数据类型 … End Sub
(6)在ReDim语句中可以定义多个动态数组,但是这些数组必须都已事先用不带维数和界限的数组声明语句进行了声明。例如: Dim
a11%(),a12$(),a13!()''先声明 Private Sub Form_Click() ReDim
a11(2,3),a12(4,5),a13(5,6,7) … End Sub
2.动态数组使用举例【例5.3】请编程,输出杨辉三角形,其一般形式如下。 1 11 121 1331 14641 15101051
……
为了输出杨辉三角形,首先找到形成上述矩阵的规律:对角线和每行的第1列均为1,其余各项是它的上一行中前一个元素和上一行的同一列元素之和;从而可以得出形成矩阵数据的一般规律:a(i,j)=a(i-1,j-1)+a(i-1,j)。
1)控件及属性控件及属性如表5.3所示。表5.3控件及属性 控件名称(Name)属性文本框Label1Caption=“杨辉三角形”
图片框Picture1 按钮Command1Caption=“显示” 2)布局界面布局如图5.5所示。 图5.5界面布局 3)代码
Option Base 1 Dim a%() ''显示按钮代码 Private Sub Command1_Click() Dim m%
m=Val(InputBox("请输入要显示杨辉三角形的级数m(小于等于14的正整数)","获取显示级数",6)) If(m
1 Or m 14)Then MsgBox"请输入大于等于3小于等于14的整数",64,"杨辉三角形" Exit Sub
End If ReDim a(m,m) Picture1.Cls For i=1 To m a(i,1)=1:a(i,i)=1
Next i For i=3 To m For j=2 To i-1 a(i,j)=a(i-1,j-1)+a(i-1,j) Next
j Next i Dim n%,k% n=42 For i=1 To m Picture1.Print Tab(n); k=n For
j=1 To i Picture1.Print Tab(k); Picture1.Print
Format(a(i,j),"@@@@@@"); k=k+6 Next j Picture1.Print n=n-3 Next i
End Sub 4)运行结果运行结果如图5.6所示。 图5.6运行结果