Dynamic Arrays in Types
 
Written by rdc

介绍


类型定义中的动态数组是非常有用的功能,但FreeBasic在1.00.0之前不支持它。或者说,它不直接在该版本之前支持它。但是,您可以通过使用指针和相关的内存函数来创建动态数组。

一个数组只是一个连续的存储块,它保存一定的数据类型。FreeBasic中的数组使用数组描述符来描述数组中包含的数据,您可以使用相同的技术在类型中构建动态数组。type-def中需要的两个元素是指向特定数据类型的指针和大小指示符。

然后,您可以使用ptr字段将内存块赋值到所需的大小,并将该大小保存在大小指示符字段中。大小字段用于告诉您数组中当前有多少个元素。数组初始化后,可以使用指针索引来访问数组中的每个元素。

得到点(呃)在代码


以下程序说明了创建,初始化和调整动态类型定义数组的步骤。
'Define type:
'size is current size of array
'darray will contain array data
Type DType
    size As Integer
    darray As Integer Ptr
End Type

'Create an instance of type
Dim myType As DType
Dim As Integer i, tmp

'Create enough space for elements
myType.darray = CAllocate(5, SizeOf(Integer))
'Set the length of the array
'in the array size indicator
myType.size = 5

'Load data into array
For i = 0 To myType.Size - 1 
    myType.darray[i] = i
Next

'Print data
For i = 0 To myType.Size - 1
    Print "darray[";i;" ]:";myType.darray[i]
Next
Print "Press any key..."
Sleep
Print

'Save the current array size
tmp = myType.size
'Now resize the array
myType.darray = Reallocate(myType.darray, 10)
'Set the length indicator
myType.size = 10

'Load in data into new allocation
For i = tmp To myType.Size - 1
    myType.darray[i] = i
Next

'Print out contents
For i = 0 To myType.Size - 1
    Print "darray[";i;" ]:";myType.darray[i]
Next
Print "Press any key..."
Sleep

'Free allocated space
Deallocate myType.darray

End


怎么运行的


第一步当然是定义类型def:
Type DType
    size As Integer
    darray As Integer Ptr
End Type

由于这只是一个例子,类型中只有两个元素,一个大小指示符和数组指针。请注意,数组指针被定义为整数ptr。当您定义一个指向特定类型的指针时,您将创建一个“键入”指针。编译器可以使用此类型的信息进行检查,以确保放入数组的值是有效的,并且还将使用该信息进行指针运算。

下一步是定义工作变量。
Dim myType As DType
Dim As Integer i, tmp

这里创建一个类型的实例,以及在下面的代码中使用的一些工作变量。警告:您必须初始化数组指针才能使用它;使用未初始化的ptr可能会导致程序崩溃,系统锁定和各种不良事情。
myType.darray = CAllocate(5, SizeOf(Integer))
myType.size = 5

这两行代码初始化数组指针以保存5个整数。Callocate用于赋值内存段,因为Callocate会将段初始化为0。

大小字段存储阵列的当前长度。现在,您可以通过简单地将赋值中的字节数除以整数的大小来计算数组的大小,但是使用类型中的大小指示器会更清晰,并在程序中保存计算。

For i = 0 To myType.Size - 1 
    myType.darray[i] = i
Next

这段代码用一些值加载数组。您可以看到为什么保存阵列的大小简化了编码过程。由于数组是一个类型化的指针,您可以使用指针索引方法访问数组,这几乎像访问预定义的数组一样。

For i = 0 To myType.Size - 1
    Print "darray[";i;" ]:";myType.darray[i]
Next

本节简单地使用与加载数组相同的方法打印出值。

当然,这应该是一个动态的数组,所以你应该能够调整数组的大小,这正是下一节的代码。
tmp = myType.size
myType.darray = Reallocate(myType.darray, 10)
myType.size = 10

第一行代码保存阵列的当前大小,以便在不覆盖任何现有数据的情况下初始化新的内存段。你会看到这一点。

第二行使用Reallocate函数调整内存段的大小,即调整数组的大小。在这种情况下,数组正在变大;您当然可以使阵列更小。如果您要使数组更小,则不会在新段中的任何数据将丢失,正如您所期望的那样。

上面的最后一行代码将新的数组大小保存在大小指示器中。

For i = tmp To myType.Size - 1
    myType.darray[i] = i
Next

在这里,您可以看到为什么保存了旧阵列大小。在For语句中,初始化过程遍历新添加的索引,将数据存储在内存段中。这就像在正常数组上使用Redim Preserve语句。

For i = 0 To myType.Size - 1
    Print "darray[";i;" ]:";myType.darray[i]
Next

这个代码部分只是打印出新的值。

Deallocate myType.darray

这是至关重要的。您应该总是释放您在程序中创建的任何已赋值的内存,以防止内存泄漏。

运行程序时,应该会看到以下输出:
darray[ 0 ]: 0
darray[ 1 ]: 1
darray[ 2 ]: 2
darray[ 3 ]: 3
darray[ 4 ]: 4
Press Any key...

darray[ 0 ]: 0
darray[ 1 ]: 1
darray[ 2 ]: 2
darray[ 3 ]: 3
darray[ 4 ]: 4
darray[ 5 ]: 5
darray[ 6 ]: 6
darray[ 7 ]: 7
darray[ 8 ]: 8
darray[ 9 ]: 9
Press Any key...

第一个打印出来显示原始的数组。第二个打印出来显示新调整的数组。



从fbc版本1.00.0,在UDT内部支持动态数组字段作为非静态成员


通过使用动态数组字段作为UDT内的非静态成员(现在支持的功能),上一个转换为fbc版本1.00.0或更高版本的示例:
'Define type (for fbc version >= 1.00.0):
'darray will contain array data
Type DType
    darray(Any) As Integer
End Type

'Create an instance of type
Dim myType As DType
Dim As Integer i, tmp

'Create enough space for elements
ReDim myType.darray(4)

'Load data into array
For i = 0 To UBound(myType.darray)
    myType.darray(i) = i
Next

'Print data
For i = 0 To UBound(myType.darray)
    Print "darray(";i;" ):"; myType.darray(i)
Next
Print "Press any key..."
Sleep
Print

'Save the current array upper bound
tmp = UBound(myType.darray)
'Now resize the array
ReDim Preserve myType.darray(10)

'Load in data into new allocation
For i = tmp + 1 To UBound(myType.darray)
    myType.darray(i) = i
Next

'Print out contents
For i = 0 To UBound(myType.darray)
    Print "darray(";i;" ):";myType.darray(i)
Next
Print "Press any key..."

Sleep