做移动网站,php网站建设一流程,网上定做相册,旅游网络营销的渠道有哪些5.1.4 动态数组
在传统的Pascal中#xff0c;数组的大小是固定的#xff0c;并且在声明数据类型时限制了元素的数量。然而#xff0c;Object Pascal支持动态数组的直接和本地实现。 注解#xff1a;“直接实现动态数组” 与使用指针和动态内存分配来获得类似效果的方法…5.1.4 动态数组
在传统的Pascal中数组的大小是固定的并且在声明数据类型时限制了元素的数量。然而Object Pascal支持动态数组的直接和本地实现。 注解“直接实现动态数组” 与使用指针和动态内存分配来获得类似效果的方法截然不同… 后者代码非常复杂且容易出错。 顺便说一句动态数组是大多数现代编程语言中唯一的一种结构形式。 动态数组是动态分配的并进行引用计数使得参数传递更快因为只传递引用而不是完整数组的副本。当您完成使用数组时可以通过将其变量设置为nil或将长度设置为零来清除数组由于动态数组是引用计数的编译器将自动释放内存。请注意这仅适用于数组项使用的内存如果数组保存对其他位置内存的引用如对象引用您需要确保在释放数组本身之前清理这些对象使用的内存。
使用动态数组时您可以声明一个数组类型而不指定元素的数量然后使用SetLength过程设置数组的大小
varArray1: array of Integer;begin// 这将导致运行时范围检查错误// Array1[0] : 100;SetLength(Array1, 10);Array1[0] : 100; // 这是可以的
end; 在为数组设定长度并在堆上分配所需的内存之前你不能使用数组。如果你这样做要么会出现范围检查错误如果相应的编译器选项处于激活状态要么会在 Windows 平台上出现访问违规Access Violation或者在其他平台上出现类似的内存访问错误。SetLength 调用会将所有的值设置为零。数组初始化以后你就可以立即开始读写数组值而不必担心内存错误除非超越了数组边界。
如果确实需要显式分配内存你也不必直接释放内存。在上面的代码片段中当代码结束且 Array1 变量退出作用域时编译器会自动释放其内存在本例中是已分配的 10 个整数。因此虽然可以将动态数组变量赋值为 nil 或调用 SetLength 时赋值为 0但一般不需要这样做也很少这样做。
请注意SetLength 过程也可以用来调整数组的大小如果要增大数组则不会丢失当前的内容如果要缩小数组则会丢失一些元素。由于在最初的 SetLength 调用中只指定了数组的元素个数动态数组的索引总是从 0 开始直到元素个数减 1。换句话说动态数组不支持经典静态 Pascal 数组的两个特性非零低限和非整数索引。同时动态数组与大多数基于 C 语法的语言中数组的工作方式更为相像。
要查询动态数组的当前大小与静态数组一样你可以使用 Length、High 和 Low 函数。但是对于动态数组Low 总是返回 0而 High 总是返回长度减 1。这意味着对于一个空数组High 返回-1仔细想想这是一个奇怪的值因为它比 Low 返回的值低。
因此在 DynArray 示例中我使用自适应循环从动态数组中填充和提取信息。这是类型和变量定义
typeTIntegersArray array of Integer;varIntArray1: TIntegersArray; 使用以下循环为数组分配内存并用匹配索引的值填充
varI: Integer;beginSetLength(IntArray1, 20);for I : Low(IntArray1) to High(IntArray1) doIntArray1[I] : I;
end; 第二个按钮的代码既显示每个值又计算平均值类似于先前示例中的代码但包含在一个循环中
varI: Integer;Total: Integer;beginTotal : 0;for I : Low(IntArray1) to High(IntArray1) dobeginInc(Total, IntArray1[I]);Show(I.ToString : IntArray1[I].ToString);end;Show(Average: (Total / Length(IntArray1)).ToString);
end; 这段代码的输出是相当明显的大部分被省略
0: 0
1: 1
2: 2
3: 3
...
17: 17
18: 18
19: 19
Average: 9.5 除了Length、SetLength、Low和High之外还有其他一些常见的过程可用于数组比如Copy函数它允许您复制数组的一部分或全部。请注意您还可以将一个数组从一个变量分配给另一个变量但在这种情况下您不是在进行完全复制而是使两个变量引用相同的内存中的同一个数组。
仅在DynArray示例的最后部分中有略微复杂的代码它以两种不同的方式将一个数组复制到另一个数组
使用Copy函数该函数在新的数据结构中使用单独的内存区域复制数组数据使用赋值运算符它实际上创建了一个别名即一个新变量引用相同的内存中的相同数组
在这一点上如果您修改新数组的元素之一您将会影响原始版本或者根据复制的方式而不影响它。这是完整的代码
varIntArray2: TIntegersArray;IntArray3: TIntegersArray;begin// 别名IntArray2 : IntArray1;// 单独的复制IntArray3 : Copy(IntArray1, Low(IntArray1), Length(IntArray1));// 修改项目IntArray2[1] : 100;IntArray3[2] : 100;// 检查每个数组的值Show(Format([%d] %d -- %d -- %d, [1, IntArray1[1], IntArray2[1], IntArray3[1]]));Show(Format([%d] %d -- %d -- %d, [2, IntArray1[2], IntArray2[2], IntArray3[2]]));
end;您将得到的输出如下
[1] 100 -- 100 -- 1
[2] 2 -- 2 -- 100 对IntArray2的更改会波及到IntArray1因为它们只是对同一物理数组的两个引用对IntArray3的更改是独立的因为它有数据的独立副本。
动态数组的本地操作
动态数组在Delphi XE7中引入了对常量数组的赋值和连接的支持。以下是一个示例演示了这些操作
varDI: array of Integer;I: Integer;beginDI : [1, 2, 3]; // 初始化DI : DI DI; // 连接DI : DI [4, 5]; // 混合连接for I in DI dobeginShow(I.ToString);end;
end; 注意此代码中使用for-in循环遍历数组元素这是DynArrayConcat示例的一部分。这些数组可以基于任何数据类型从简单的整数到记录和类。
除了赋值和连接之外还可以在动态数组上使用对字符串常见的Insert和Delete等函数。
以下是使用Insert和Delete的示例
varDI: array of Integer;I: Integer;beginDI : [1, 2, 3, 4, 5, 6];Insert([8, 9], DI, 4);Delete(DI, 2, 1); // 删除第三个项目zero-based index
end;