Introduction To Arrays
 
Written by rdc

数组可能是FreeBasic中可用的最有用的编程结构。您将尝试用编程解决方案解决的许多问题涉及以表格格式排列的数据,数组是管理此类数据的理想选择。了解数组是成为有能力的程序员的关键技能。

数组是单个或复合数据类型的连续内存段。您可以将数组视为表,其中包含行和数据列。数组可以有一行或多行,每行可以有一个或多个列。行数和列数定义了数组的维数。FreeBasic对数组使用row-major方案,这意味着第一个维引用了具有多个维度的数组中的行。FreeBasic在数组中支持多达八个维度。

一维数组


具有单个行的数组称为一维数组。如果一个数组是一个单维数组,那么这个行在声明中没有定义,只有行中的列数。由于阵列至少需要一行,所以在这种情况下,行被理解为存在。以下代码片段使用FreeBasic中可用的不同数组定义方案创建单维整数数组。

Dim myArray(10) As Integer

Dim myArray(1 To 10) As Integer


第一种方法将定义一个单行和11列数组,列索引(数字)范围从0到10。第二种方法使用To关键字定义下限和上限。这里的索引范围是1到10。

一维数组索引


您可以使用索引值访问数组的每个元素。在单维数组的情况下,索引将引用默认行中的列号。格式是使用数组变量,索引用括号括起来。

myArray(5) = 7


这将列数组中的列5设为7。

myInt = myArray(5)


这将myInt的值设置为myArray中第5列的当前值。

二维数组


二维数组是具有多个行的数组,以及定义的列。一个二维数组就像一个表,它有一个定义的行数,每行都有一个定义的列数。以下代码片段使用默认方法定义数组。

Dim myArray(2, 10) As Integer


第一个维度定义了数组中的行数,而第二个维定义了每行中的列数。在这个例子中,该数组有3行,编号为0到2,每行有11列,编号为0到10。

您还可以定义数组的下限和上限。

Dim myArray(1 To 2, 1 To 10) As Integer


此定义将行数设置为2,编号为1到2,列数设置为10,编号为1到10。

二维数组索引


要访问二维数组的数组元素,您将使用两个索引。第一个索引选择该行,第二个索引选择该行中的列。

myArray(1, 5) = 7


此代码将列第1列设置为第5列。

myInt = myArray(1, 5)


该代码将myInt设置为数组第1列的第5列中的当前值。

多维数组


对于三维或更多维的数组,您将使用与上述相同的格式,考虑到数组维度的进展。对于一个三维数组,第一个维是行,第二个是列,第三个是每列的z次或深度。

例如,要定义空间中的立方体,您可以使用y,x,z格式,其中y定义垂直轴,x定义水平轴,z定义深度轴。要以此格式创建数组,您可以将数组定义为:

Dim myCube(y, x, z) As Integer. 


MyCube(10, 10, 10)将创建一个具有11个垂直单位的立方体,0到10,11个水平单位,0到10和10个深度单位,0到10。要访问多维数据集的中心,您可以使用iCenter = myCube(5, 5, 5).

除非您进行一些高级数学计算,否则您可能不需要使用三维以上的数组。但是,如果您需要使用高维数组,则应用相同的原则。

动态数组


上述阵列是静态数组;在程序执行期间,数组大小不能改变。您还可以创建可以在执行期间更改大小的动态数组。动态数组对于创建数据结构(如堆栈或队列)很有用。

上面描述的数组的静态数组保存在堆上,但动态数组是从计算机的内存池中赋值的。编译器根据数组的请求维度为数组动态赋值内存。

您可以使用ReDim关键字指定一个动态数组。

ReDim myArray(1 To 5, 1 To 5) As Integer


如果在程序执行开始时不知道需要的数组边界,可以使用空索引定义数组。

Dim myArray() As Integer


在这种情况下,编译器为数组大小设置默认值0。然后,您可以在程序中的某个位置使用ReDim来设置数组边界。

ReDim和ReDim保存en


动态数组可以在执行过程中改变大小。ReDim将将数组的内容清除为默认数据类型值,而ReDim Preserve将保留现有内容,除非数组大小小于上一个大小。

数组函数


有很多功能您可以使用阵列。

复合类型数组


类型定义允许您将相关数据分组到单个实体中,并且通常您将需要多个类型的实例来完全表达数据。类型数组允许您创建可以使用数组函数轻松管理的类型定义的多个实例。此用法的一个示例可能是您的RPG的库存系统,编辑器中的一系列文档描述以及随机访问数据库中的一组员工记录。

您可以像任何内在数据类型一样创建类型的数组。以下代码片段说明了语法。

Type myPoint
    row As Integer
    col As Integer
End Type

Type myLine
    p1 As myPoint
    p2 As myPoint
    char As String * 1
End Type

Dim myLineSet (1 To 3) As myLine


代码定义了一组3行,端点p1p2,其中每个端点位于行和列。您可以通过使用数组索引和点运算符的组合来访问数组元素。

myLineSet(1).p1.row = 1
myLineSet(1).p1.col = 1
myLineSet(1).p2.row = 10
myLineSet(1).p2.col = 10
myLineSet(1).char = Chr(219)


类型中的数组


您不仅可以创建复合类型的数组,还可以将数组作为复合类型的字段。通过用数组替换p1p2可以更有效地写出上面的例子。

Type myPoint
    row As Integer
    col As Integer
End Type

Type myLine
    pts(1 To 2) As myPoint
    char As String * 1
End Type

Dim myLineSet (1 To 3) As myLine


这里ptsmyPoint的数组。要访问此结构,您将使用索引和点运算符的组合。

myLineSet(1).pts(1).row = 1
myLineSet(1).pts(1).col = 1
myLineSet(1).pts(2).row = 10
myLineSet(1).pts(2).col = 10
myLineSet(1).char = Chr(219)


myLineSet是一个数组,因此您可以使用索引值。pts是该类型的元素,因此您需要使用点运算符进行限定。但是,pts也是一个数组,因此您可以使用索引来选择每个pts数组元素。RowcolmyPoint类型的元素,并使用点运算符访问。

为端点使用数组使您能够轻松地扩展线条定义,不仅支持线条,还支持三角形和正方形。以下代码片段显示了一个可能的定义。

Type myObj
    objid As Integer
    Union
            myLine(1 To 2) As myPoint
        myTriangle(1 To 3) As myPoint
        mySquare(1 To 4) As myPoint
    End Union
    char As String * 1
End Type


objid字段将指明联合定义中包含哪种类型的对象。也就是说,1可以指示线,2可以指示三角形,并且3可以指示正方形。由于定义定义了单个对象,因此Union用于封装端点数组以最大化内存使用率。

要将对象打印到屏幕上,您将检查objid,然后在适当的端点阵列定义上使用Lbound和Ubound,打印与对象类型对应的行数。

您可以对此程序进行一个进一步的改进之一是向类型定义添加一个函数指针,然后编写与要打印的对象类型相对应的打印例程。使用这种技术将使您能够通过简化向对象类型定义添加新对象的过程来进一步扩展代码的有用性。

例如,如果您需要能够描述一个多维数据集,那么您只需将一个新数组添加到该联合体中,添加一个多维数据集打印函数,该类型定义就可以通过添加几行代码来打印多维数据集同时保持原有的功能。

阵列初始化


在使用Dim语句时,可以初始化具有值的数组,方法与初始化任何其他内在数据类型类似,并键入定义。以下代码片段说明了使用一维数组的语法。

Dim aArray(1 To 5) As Integer => {1, 2, 3, 4, 5}


此代码片段使用5个元素对整数数组进行维度,然后将元素设置为包含在大括号内的列表。箭头运算符= >告诉编译器应该使用Dim语句之后的列表来初始化数组。

您还可以以相同的方式对多维数组进行维度,如下面的代码片段所示,通过指定括号内的数据块。

Dim bArray(1 To 2, 1 To 5) As Integer => {{1, 2, 3, 4, 5},{6, 7, 8, 9, 10}}


在这个例子中,第一个块{1, 2, 3, 4, 5}对应于行1,第二个块{6, 7, 8, 9, 10}对应于行2。请记住,FreeBasic数组是行主,因此该行在列之前指定。当您以这种方式初始化数组时,必须确保定义的元素数将适合数组。

类型阵列初始化


您不仅可以初始化一组简单的数据类型,还可以使用复合类型初始化数组。以下代码片段说明了一个类型数组,其中包含一个数组作为该类型的元素。

Type aType
    a As Integer
    b As Byte
    c(1 To 2) As String * 10
End Type

Dim As aType myType(1 To 2) => { (1234, 12, {"Hello", "World"}), (5678, 24, {"From", "Freebasic"})} 


大括号表示这是一个数组初始化,而括号表示类型初始化。由于该类型具有嵌入式阵列,因此您可以使用大括号将数据加载到嵌入式阵列中,就像独立阵列一样。如果嵌入式数组是一个多维数组,那么您将需要将{和}中的每一行包装成独立的数组。

使用-exx编译器开关


-exx编译器开关将在程序中启用错误和边界检查。如果您在程序中的数组范围之外,编译器将在程序运行时生成“超出范围”错误。

这对调试程序和找到与数组相关的问题非常有帮助。-exx还会通知您Null指针赋值,所以在使用指针时也是非常有用的。

使用-exx确实为您的程序添加了一些额外的代码,所以一旦你的程序正常运行,你将需要编译没有-exx开关的程序。