Delphi 之 第八课 动态数组

Delphi 4 的动态数组

传统的Pascal 语言其数组大小是预先确定的,当你用数组结构声明数据类型时,你必须指定数组元素的个数。专业程序员也许知道些许动态数组的实现技术,一般是采用指针,用手工分配并释放所需的内存。

Delphi 4中增加了非常简单的动态数组实现方法,实现过程效仿我前面讲过的动态长字符串。与长字符串一样,动态数组的内存动态分配并且引用记数,不过动态数组不支持 copy-on-write 技术。这不是个大问题,因为你可以把变量值设置为nil释放数组内存。

这样你就可以声明一个不指定元素个数的数组,并用SetLength 过程给数组分配一个特定大小的内存,SetLength 过程还可以改变数组大小而不影响其内容,除此外还有一些字符串过程也可用于数组,如Copy 函数。

以下摘录的代码突出了一点,这就是:定义数组后必须先为它分配内存,然后才能开始使用:

procedure TForm1.Button1Click(Sender: TObject);
var
  Array1: array of Integer;
begin
  Array1 [1] := 100; // error
  SetLength (Array1, 100);
  Array1 [99] := 100; // OK
  ...
end;

如果你只定义一个数组元素个数,那么索引总是从0开始。Pascal 中的普通数组既能用不为零的下标,也能用非整数的下标,但动态数组均不支持这两种下标。象普通数组一样,你可以通过Length、High和Low 函数了解到动态数组的状况,不过对于动态数组,Low 函数返回值总是0,High函数返回数组大小减1,这意味着空的动态数组其函数High返回值是-1,这是一个很怪的值,因为它比Low的返回值还小。

图 8.1: 例 DynArr 窗体

以上作了简短的介绍,现在举个简例,例名DynArr ,见图8.1。例子实在是很简单,其实动态数组没有什么特别复杂地方。我想通过该例说明几个程序员可能犯的错误。程序中声明了两个全程数组并在OnCreate 事件中初始化了第一个数组:

var
  Array1, Array2: array of Integer;

procedure TForm1.FormCreate(Sender: TObject);
begin
  // allocate
  SetLength (Array1, 100);
end;

这样就把数组所有值设置为0。完成这段代码你马上就能读写数组元素的值,而不用害怕内存出错,当然条件是你没有试图访问超过数组上界的元素。为了更好地初始化,程序中添加了一个按钮,执行数组元素赋值操作:

procedure TForm1.btnFillClick(Sender: TObject);
var
  I: Integer;
begin
  for I := Low (Array1) to High (Array1) do
    Array1 [I] := I;
end;

Grow 按钮用于修改数组大小,但并不影响数组内容。单击Grow 按钮后,你可以用Get value按钮进行检验:

procedure TForm1.btnGrowClick(Sender: TObject);
begin
  // grow keeping existing values
  SetLength (Array1, 200);
end;

procedure TForm1.btnGetClick(Sender: TObject);
begin
  // extract
  Caption := IntToStr (Array1 [99]);
end;

Alias 按钮的OnClick 事件代码稍复杂些,程序通过 := 算子把一个数组拷贝给另一个数组,从而有效地创建了一个别名(一个新变量,但引用内存中同一数组)。从中可见,如果你改变了其中一个数组,那么另一个同样也会改变,因为它们指向同一个内存区:

procedure TForm1.btnAliasClick(Sender: TObject);
begin
  // alias
  Array2 := Array1;
  // change one (both change)
  Array2 [99] := 1000;
  // show the other
  Caption := IntToStr (Array1 [99]);

在btnAliasClick 事件中增加了两部分操作内容。第一部分是数组等同测试,不过并不是测试实际的数组元素,而是测试数组所引用的内存区,检测变量是不是内存中同一数组的两个别名:

procedure TForm1.btnAliasClick(Sender: TObject);
begin
  ...
  if Array1 = Array2 then
    Beep;
  // truncate first array
  Array1 := Copy (Array2, 0, 10);
end;

btnAliasClick 事件的第二部分内容是调用Copy 函数。该函数不仅把数据从一个数组移到另一个数组,而且用函数创建的新数组取代第一个数组,结果变量Array1 所引用的是11个元素的数组,因此,按Get value 和Set value 按钮将产生一个内存错误,并且触发一个异常(除非你把范围检查range-checking 选项关掉,这种情况下,错误仍在但屏幕上不会显示异常)。虽然如此,Fill 按钮仍能正常工作,因为需要修改的数组元素由数组当前的下标范围确定。

结束语

这一章内容暂时只包括动态数组,动态数组的确是内存管理的重要组成部分,但仅仅是其中的一部分,其它内容以后会逐步添加。

本章描述的内存结构属于典型的 Windows 编程内容,这方面内容将在下一章进行讨论。

下一章: Windows 编程

时间: 2024-11-14 12:51:11

Delphi 之 第八课 动态数组的相关文章

delphi 动态数组的使用

var RowArray: array of string; i: integer; begin SetLength(ArrayRow, G2.ColumnCount-1); // 动态数组初始化 先定义长度 for i := 0 to G2.ColumnCount-1 do begin ArrayRow[i] := G2.Cells[i, G2.Selected]; // 将点击的行存入数组内,若比较不相等时,则post提交保存数据. end; end;

[转]delphi 删除动态数组的指定元素

type TArr = array of TPoint; {把数组先定义成一个类型会方便许多, 这里仅用 TPoint 测试} {删除动态数组指定元素的过程: 参数 arr 是数组名, 参数 Index 是要删除的索引} procedure DeleteArrItem(var arr: TArr; Index: Integer); var Count: Cardinal; begin Count := Length(arr); if (Count = 0) or (Index < 0) or (

【C++探索之旅】第一部分第九课:数组威武,动静合一

内容简介 1.第一部分第九课:数组威武,动静合一 2.第一部分第十课预告:文件读写,海阔凭鱼跃 数组威武,动静合一 上一课<[C++探索之旅]第一部分第八课:传值引用,文件源头>中,我们学习了函数参数的不同传递形式:值传递和引用传递,也学习了如何用头文件和源文件来更好地组织项目. 在不少程序中,我们都需要使用多个相同类型的变量.例如:一个网站的用户名列表(一般是string类型):或者一场比赛的前10个最佳得分(一般是int类型). 类似地,C++和大多数编程语言一样,也有将多个相同类型的数据

【C语言探索之旅】 第一部分第八课:第一个C语言小游戏

? 内容简介 1.课程大纲 2.第一部分第八课:第一个C语言小游戏 3.第一部分第九课预告: 函数 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写三个游戏. C语言编程基础知识 什么是编程? 工欲善其事,必先利其器 你的第一个程序 变量的世界 运算那点事 条件表达式 循环语句 实战:第一个C语言小游戏 函数 练习题 习作:完善第一个C语言小游戏 C语言高级技术 模块化编程 进击的指针,C语言王牌 数组 字符串 预处理 创建你自己的变量类型 文

【C语言探索之旅】 第二部分第八课:动态分配

内容简介 1.课程大纲 2.第二部分第八课: 动态分配 3.第二部分第九课预告: 实战"悬挂小人"游戏 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写三个游戏. C语言编程基础知识 什么是编程? 工欲善其事,必先利其器 你的第一个程序 变量的世界 运算那点事 条件表达式 循环语句 实战:第一个C语言小游戏 函数 练习题 习作:完善第一个C语言小游戏 C语言高级技术 模块化编程 进击的指针,C语言王牌 数组 字符串 预处理 创建你自己

【C++探索之旅】第一部分第八课:传值引用,文件源头

内容简介 1.第一部分第八课:传值引用,文件源头 2.第一部分第九课预告:数组威武,动静合一 传值引用,文件源头 这一课的标题有点怪.其实是由这一课的几个重点内容结合起来取的名,慢慢学习就知道啦. 上一课<[C++探索之旅]第一部分第七课:函数效应,分而治之>中,我们初步认识了函数. 不过不要高兴得太早,你以为函数就这样离你远去了嘛?怎么可能,函数将伴随一生好吗,只要你继续编程的话.哈哈,所以你是跑不掉了~ [小编,都跟你签了协议了,没吃药不要随便出来溜达] 这一课我们就继续深入学习与函数相关

【C语言探索之旅】 第二部分第三课:数组

内容简介 1.课程大纲 2.第二部分第三课: 数组 3.第二部分第四课预告:字符串 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写三个游戏. C语言编程基础知识 什么是编程? 工欲善其事,必先利其器 你的第一个程序 变量的世界 运算那点事 条件表达式 循环语句 实战:第一个C语言小游戏 函数 练习题 习作:完善第一个C语言小游戏 C语言高级技术 模块化编程 进击的指针,C语言王牌 数组 字符串 预处理 创建你自己的变量类型 文件读写 动态分配

Delphi 之 第七课 字符串操作

字符串类型 在Borland公司的Turbo Pascal和16位Delphi中,传统的字符串类型是一个字符序列,序列的头部是一个长度字节,指示当前字符串的长度.由于只用一个字节来表示字符串的长度,所以字符串不能超过255个字符.这一长度限制为字符串操作带来不便,因为每个字符串必须定长(确省最大值为255),当然你也可以声明更短的字符串以节约存储空间. 字符串类型与数组类型相似.实际上一个字符串差不多就是一个字符类型的数组,因为用[]符号,你就能访问字符串中的字符,这一事实充分说明了上述观点.

NeHe OpenGL教程 第二十八课:贝塞尔曲面

转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线教程的编写,以及yarn的翻译整理表示感谢. NeHe OpenGL第二十八课:贝塞尔曲面 贝塞尔曲面: 这是一课关于数学运算的,没有别的内容了.来,有信心就看看它吧. 贝塞尔曲面 作者: David Nikdel ( [email protected] ) 这篇教程旨在介绍贝塞尔曲面,希望有比我更