1、数组的引出
数组——用一个名字来代表的按一定顺序排列的一组具有相同属性、类型的数据或变量。
数组元素——数组中的每个数据或变量称为数组元素。
数组名的命名规则——和变量名的规则相同。
例如用户要记录一个班级的同学的名字,可以为每一个同学定义一个变量用来记录他们的名字,例如studentl、student2……。但是这样做显然是一种非常笨的方法,因为这些变量的类型都是相同的,并且功能相似,都是用来记录学生名字的。因此,采用数组的方法就会简单得多,利用数组只需要定义一个数组变量student(下标),然后利用数组的索引就可以识别数组中的每一个元素。如下图所示,显示了用一维数组存储学生姓名的方法。
张三 |
李四 |
王五 |
徐六 |
…… |
student(l) |
student(2) |
student(3) |
student(4) |
…… |
注意:
- 用一个统一的数组名和下标来唯一地确定数组中的元素,更改其中一个元素并不会影响其它元素。
- 数组可以声明为任何基本数据类型的数组,包括用户自定义类型,数组中的元素可以属于同一个数据类型。也可以是不同数据类型,当数据类型为Variant时,各个元素能够包含不同种类的数据(对象、字符串、数值等等)。
2、数组分类
按照长度分——可以分成两种类型的数组:一种是固定大小的数组,这种数组总是保持同样的大小称静态数组(定长数组),另一种是在运行时大小可以改变的称动态数组。
按照级数分——可以分为一维数组和多维数组。
前面介绍的数组主要是一维数组,这种数组适用于存放一系列没有树型关系的一维数据,如姓名、单据等数据。但如果数据中有层次关系,例如要记录一个学校所有班级的学生记录,当然也可以用一维数组来实现,但是这样就失去了学生所在班级的信息,如果两个班级中有重名的学生,就更加无法区分。这时,利用多维数组就可以很方便地解决这一问题。
我们可以将这样的数据存储在一个二维数组中,二维数组有两个索引,第一个表示行(数组中的班级顺序),第二个表示列(班级中的成员)。如下表,显示了用二维数组存储班级成员的方法。
班级1 |
班级2 |
班级3 |
… |
张三 |
赵伟 |
孔明 |
…0 |
李四 |
齐秦 |
刘备 |
…1 |
王五 |
王菲 |
孙权 |
…2 |
朱六 |
于明 |
关羽 |
…3 |
…0 |
…1 |
…2 |
… | |
例如王菲是第三行、第二列,可表示是为Student(2,1)。
注意:
缺省条件下,数组的第一个元素的下标为0。
在增加数组的维数时,数组所占的存储空间会大幅度增加,所以要慎用多维数组。使用Variant数组时要更加小心因为他们需要更大的存储空间。
3、数组的定义与声明
在使用数组之前,一般要声明数组,当然也可以采用隐式声明的方法。声明数组的方法与声明各种类型的变量一样,可以用Dim,Private,Public或Static来声明,只不过声明数组时需要设置数组的上下界,也就是数组下标索引的起始值和中止值。
(1)静态数组:
其声明的语法如下:
Dim│Private│Public│Static 数组名([下标下界 To]下标上界) [As 数据类型]
说明:
数组名后是圆扩弧“( )”扩起来,不能采用其它符号。
如果不指明数组的下标下界,系统默认为是0,数组的下标上界,使用长整型(Long)数据,在VB中规定上界不得超过2,147,483,647。
下标的下界不能大于下标的上界;
可以用变量名或常数名(以及实数)作为下标边界,当下标的边界是常数名时,数组的大小固定(静态数组),当下标的边界是变量名时,数组的大小可作动态定义(动态数组)。
例(见教材P43):
★ Dim A(10) As Integer '表示数组名为A,缺省下标界为0,上界为10的有11个整型元素的数组,即:从A(0),A(1)到A(10);
★ Dim B(1 To 20) As Integer'表示数组名为B,下标下界为1,下标上界为20的,有20个整型的元素;
★ Dim BirthDay (1 To 10) As Date '表示BirthDay是一个索引从1到10的Date型数组。
★ Dim DayArray (50)'表示变量是一个有51个索引元素的Variant数组;
★ Public Class (10) As String '声明一个长度为11的全局整型数组Class;
★ Dim Matrix(3,4) As Integer '表示变量是一个二维整型数组;
★ Dim MyMatrix(1 To 5,4 To 9, 3 To5) As Double '表示变量是一个显示指定了上下界的三维double数组;
为数组赋初值可以采用循环语句。如:
Dim I As Integer For I=0 To 11 C(I)=I 'C(0)、C(1)、……C(11) Next I
例题:下面的练习使用一个名为Temperatures的一维公用数组来记录一周七天的日最高气温。
界面:
在窗体上添加3个命令按钮,窗体的AutoRedraw属性设定为True。——当使用Print方法在窗体中显示信息时,请始终将窗体的AutoRedraw属性设定为True。这样,当窗体被另一个窗口遮盖然后该窗体重新显示时,VisualBasic将自动重新绘制屏幕。
本例没有使用强制声明“Option Explicit”语句。
代码:
Dim Temperatures(6) As Variant
Private Sub Command1_Click() Cls Prompt$ = "Enter the high temperature." For i% = 0 To 6 Title$ = "Day" & i% Temperatures(i%) = InputBox(Prompt$, Title$) Next i% End Sub
Private Sub Command2_Click() Cls Print "High Temperatures for the week:" Print For i% = 0 To 6 Print "Day "; i%, Temperatures(i%) Total! = Total! + Temperatures(i%) Next i% Print Print "Average high temperature: "; Total! / 7 End Sub
Private Sub Command3_Click() End End Sub
说明:该程序演示如何在程序中使用数组存放和处理一组相关数值。通过使用InputBox函数和For...Next循环,气温值被赋值给数组。循环中循环计数器被用来索引数组中的每个元素。数组内容通过使用For...Next循环和Print(打印)方法显示在窗体中,接着平均最高气温就被计算并显示出来了。
也可利用For循环嵌套有效地处理多维数组。例:
Dim i As Integer,j As Integer '设置计数器 Dim class(14) As String '定义班级名称数组 Dim studentname(14,35) As String '定义学生姓名数组 …… '为班级数组赋值 …… '为学生数组赋值 For i=0 To 14 For j=0 To 35 If studentname(i,j)="张三" Then MsgBox "张三在"十class(i) End If Next j Next i
(2)动态数组
在有些情况下,用户可能不知道需要多大的数组,这时就需要用一个能够改变大小的数组,这就是动态数组。动态数组可以在任何时侯改变大小。在VB中,动态数组是最灵活、最方便的一种数组。利用动态数组还有助于有效管理内存,因为动态数组是使用时才开辟内存空间,在不使用这个数组时,还可以将内存空间释放给系统。这样就可以最大限度地节省内存,提高运行速度。
创建动态数组需要2步,第一步和固定长度数组(静态数组)类似,用Dim语句(或Private、Public、Static)声明,但是不要指定维数。如:
Dim MyArry () As Integer
第二步在以后的实际程序中,当要用到该数组时,再用ReDim语句分配实际的元素个数,这时需要确定元素的个数。如前面声明的数组MyArry,可以用下面语句将它定义为一个二维数组:
ReDim MyArry(10,10)
ReDim语句只能出现在过程中。与Dim语句、Static语句这些变量声明语句不同,ReDim语句是—个可执行语句,ReDim语句可以改变元素数目以及上下界,但在第一个ReDim语句定义了数组维数之后,就不能够再改变数组维数(最多能定义的维数是60),只能改变数组边界。如:
Dim MyArry () As Single '声明动态数组 ReDim MyArry(30,20,10) '重新定义数组 ReDim MyArry(50,23,21) '再次重新定义数组(这时不能再改变维数)
每次执行ReDim语句时,Visual Basic会把动态数组中的数值重新初始化一遍,当前存储在数组中的值都会全部丢失。但是用户有时希望只改变数组大小,但不丢失数组中的数据。这时,可以使用带Preserve关键字的ReDim语句。其格式为:
ReDim Preserve 数组名([下标下界 To]下标上界) [As 数据类型]
例如:
ReDim MyArry(50,23,21)
ReDim Preserve MyArry(50,23,50)
注意:用Preserve只能在改变数组的最后一维大小时,保留数组的数据。对一维数组来说,所有数据都会保留,而对于多维数组,只能改变最后一维的大小,才能保留全部数组数据,否则出错。
(3)Option Base语句
Option Base语句在模块级别中使用,用来声明数组下标的缺省下界。
语法结构:
Option Base{0|1}
说明:
缺省状态下数组下界为0,此时无需使用Option Base语句。如果使用该语句规定数组下界1,则必须在模块的数组声明之前使用Option Base语句。
Option Base语句只影响位于包含该语句的模块中的数组下界。
对于那些在声明中用To子句来设定维数的数组而言,它们可以用任何整数作为下界而不受Option Base语句限制。
(4)Lbound 函数和Ubound函数
Lbound 函数和Ubound函数都是返回一个Long型数据,Lbound 函数得到的值为指定数组维可用的最小下标,而Ubound函数得到的是最大下标。
语法结构:
Lbound (数组名[,指定的维数])
Ubound (数组名[,指定的维数])
式中的数组名是必选项。指定的维数是可选的,表明指定返回哪一维的下界。“1”表示第一维;“2”表示第二维;以此类推。如果省略指定的维数,就默认为1。如:
Dim A(1 to 100,3,-3 to 4) As Integer'假定没有使用Option Base语句改变数组下界的默认值。
对这个数组A使用Lbound 和Ubound函数,其返回值如下表:
语句 |
返回值 |
Lbound (A,1) Lbound (A,2) Lbound (A,3) Ubound (A,1) Ubound (A,2) Ubound (A,3) |
1 0 -3 100 3 4 |
说明:
所有维的缺省下界取决于Option Base语句的设置,它的值可以是0或1。可以看出使用Lbound 和Ubound函数,可用于确定一个数组中元素的个数。
(5)数组的高级功能
数组的一般功能——如前所述,数组可用来存储成组的变量。
数组的高级功能——可以将一个数组的内容赋值给另一个数组、创建返回数组的函数,还可以创建返回数组的属性。
例:将一个数组的内容赋值给另一个数组(就好像将一个变量赋给另一个变量如Str A = Str B一样)。
如,将一字节型数组从一个位置复制到另一个位置,程序如下:
Sub ByteCopy(oldCopy() As Byte, newCopy() As Byte) '参数oldCopy()是源数组,newCopy()是目标数组
Dim i As Integer ReDim newCopy (Lbound(oldCopy) To UBound(oldCopy)) '重新定义动态数组 For i = Lbound(oldCopy) To Ubound(oldCopy) '循环赋值 newCopy(i) = oldCopy(i) Next
End Sub
一个更有效的简单的方法就是直接将一个数组赋给另外一个数组:
Sub ByteCopy(oldCopy() As Byte, newCopy() As Byte) '参数oldCopy()是源数组,newCopy()是目标数组
newCopy = oldCopy '利用数组直接进行赋值
End Sub
数组赋值规则:
关于变量赋值有一些规则。例如,虽然可以将一个声明为整型的变量赋给一个声明为长整型的变量而不会产生任何问题,但是将一个长整型变量赋给一个整型变量就很容易导致溢出错误。除了遵守有关数据类型变量之间赋值时的规则外,数组赋值还要遵从另外一些规则,包括数组维数,每一维的大小,以及数组是固定的还是动态的。
维数、数据类型不同的数组赋值考虑的几个因素
★赋值符左边的数组类型:固定数组 (Dim x(1 to 10) As Integer) 或者动态数组 (Dim x() As Integer)。
★赋值符左边数组的维数是否和赋值符右边数组的维数匹配。
★赋值符两边数组的每一维的数组元素个数是否匹配。即使数组的声明不同,维数也可能匹配。比如一个数组的每一维元素从 0 开始编号而另一个则从 1 开始,维数也可能匹配。
★赋值符两边所有元素的数据类型必须是相容的。这些规则和变量赋值的规则是一致的。
下表显示了这些因素的影响(见教材P46):
左边数组 |
维数是否匹配 |
元素个数是否匹配 |
赋值的结果 |
动态 |
否 |
是或否 |
成功。如果需要,左边将重新声明(ReDim)使其与右边匹配。 |
动态 |
是 |
否 |
成功。如果需要,左边将重新声明(ReDim)使其与右边匹配。 |
动态 |
是 |
是 |
成功 |
静态 |
是或否 |
是或否 |
失败并返回一个编译错误 |
数组赋值时的错误可能发生在编译时,也可能发生在运行时(例如,如果数据类型不能强制转换或赋值试图重新声明 (ReDim) 一个静态数组)。设计程序时要添加错误处理以确保数组在赋值之前是匹配的。
编写返回数组的函数
从一个函数返回一组值是可能实现的。例如,从一个函数返回一组字节而不必将其先转换为一个字符串然后再转换回来。
Private Sub Form_Load()
Dim b As Byte Dim i As Integer Dim ReturnArray() As Byte b = Cbyte(54) ReturnArray() = ArrayFunction(b) '调用函数 For i = Lbound(ReturnArray) To Ubound(ReturnArray) Msgbox ReturnArray(i) '通过弹出消息框循环显示数组值 Next
End Sub
Public Function ArrayFunction(b As Byte) As Byte()
Dim x(2) As Byte x(0) = b x(1) = b + CByte(200) x(2) = b + b ArrayFunction = x '返回结果为数组x。此处也可以表示为x()
End Function
在运行以上示例后, ReturnArray() 是一个三元素数组,其中包含了分配给 ArrayFunction 中数组的值。ArrayFunction 语句将一个数组作为参数传递;且数组的数据类型必须和函数的数据类型相同(在本例中是字节)。因为这是一个函数调用,传递数组时不必带括号。
注意:
- 尽管可以通过赋值给另一个数组(ArrayFunction = x())来返回一个数组,但出于性能方面的考虑,并不推荐使用这种方法。
- 必须为返回数组的函数指定一个类型,这个类型可以是 Variant。这样一来,Function X() As Variant() 是有效的而 Function X() As () 将失败。
- 当调用一个返回数组的函数时,用来保存返回值的变量也必须是一个数组,而且其数据类型必须和函数返回类型相同,否则将显示一个"类型不匹配"的错误。
|