【2017年整理】Delphi之动态数组使用总结

上传人:豆浆 文档编号:988594 上传时间:2017-05-24 格式:DOC 页数:6 大小:42.50KB
返回 下载 相关 举报
【2017年整理】Delphi之动态数组使用总结_第1页
第1页 / 共6页
【2017年整理】Delphi之动态数组使用总结_第2页
第2页 / 共6页
【2017年整理】Delphi之动态数组使用总结_第3页
第3页 / 共6页
【2017年整理】Delphi之动态数组使用总结_第4页
第4页 / 共6页
【2017年整理】Delphi之动态数组使用总结_第5页
第5页 / 共6页
点击查看更多>>
资源描述

《【2017年整理】Delphi之动态数组使用总结》由会员分享,可在线阅读,更多相关《【2017年整理】Delphi之动态数组使用总结(6页珍藏版)》请在金锄头文库上搜索。

1、Delphi 之动态数组使用总结传统的 Pascal 语言其数组大小是预先确定的,当你用数组结构声明数据类型时,你必须指定数组元素的个数。专业程序员也许知道些许动态数组的实现技术,一般是采用指针,用手工分配并释放所需的内存。 Delphi 4 中增加了非常简单的动态数组实现方法,实现过程效仿我前面讲过的动态长字符串。与长字符串一样,动态数组的内存动态分配并且引用记数,不过动态数组不支持 copy-on-write 技术。这不是个大问题,因为你可以把变量值设置为 nil 释放数组内存。这样你就可以声明一个不指定元素个数的数组,并用 SetLength 过程给数组分配一个特定大小的内存,SetLe

2、ngth 过程还可以改变数组大小而不影响其内容,除此外还有一些字符串过程也可用于数组,如 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 中的普通数组既能用不为

3、零的下标,也能用非整数的下标,但动态数组均不支持这两种下标。象普通数组一样,你可以通过 Length、High 和 Low 函数了解到动态数组的状况,不过对于动态数组, Low 函数返回值总是 0,High 函数返回数组大小减 1,这意味着空的动态数组其函数 High 返回值是-1,这是一个很怪的值,因为它比 Low 的返回值还小。图 8.1: 例 DynArr 窗体 以上作了简短的介绍,现在举个简例,例名 DynArr ,见图 8.1。例子实在是很简单,其实动态数组没有什么特别复杂地方。我想通过该例说明几个程序员可能犯的错误。程序中声明了两个全程数组并在 OnCreate 事件中初始化了第一

4、个数组: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

5、 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 :

6、= 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 Capt

7、ion := 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 函数。该函

8、数不仅把数据从一个数组移到另一个数组,而且用函数创建的新数组取代第一个数组,结果变量 Array1 所引用的是 11个元素的数组,因此,按 Get value 和 Set value 按钮将产生一个内存错误,并且触发一个异常(除非你把范围检查 range-checking 选项关掉,这种情况下,错误仍在但屏幕上不会显示异常) 。虽然如此,Fill 按钮仍能正常工作,因为需要修改的数组元素由数组当前的下标范围确定。自从有了动态数组,链表除了在教科书里出现外,已经很少在实际编程中被使用了,事实也是如此,数组的确比传统链表快得多,而且也方便的多。从 Delphi4 起,开始了内建各种类型的动态数组支

9、持。但是,对我们来说动态数组支持似乎做的不够彻底,因为 Delphi 竟然连删除、插入、移动连续元素的函数都没有提供,让人使用起来总觉得不够爽! J 。作为一名程序员,我们当然要有自己解决问题的能力,下面就让我们简单介绍一下 Delphi 下的动态数组。在 Delphi 中,数组类型有静态数组(a : array0.1024 of integer) 、动态数组(var a : array of integer) 、指针数组(即指向静态数组的指针)和开放数组(仅用于参数传递) 。静态数组、指针数组有速度快的好处,动态数组有大小可变的优势,权衡之下就有了折衷的办法,那就是定义的动态数组在必要时转换

10、为指针。动态数组声明之后,只有下面几个函数可僮鳎?o:p1 设置数组大小,可以任意缩减或增加数组大小Procedure SetLength(var S ; NewLength : integer);2 取出连续元素,复制给另一个数组变量Function Copy(s;Index,Count : integer) : array ;3 取得数组大小及上下限Function Length(s):integer;Function High(x):integer;Function Low(x):integer;值得注意的是,不加 const 或 var 修饰的动态数组会被作为形参传递,而动态数组用 c

11、onst修饰并不意味着你不能修改数组里的元素(不信你可以字自己在程序中试试。还有一点是High 函数调用了 Length 函数,所以我们在获取数组上限时最好直接用 Length(s) 函数。动态数组在内存空间中占用 4 个字节. 动态数组在内存中的分配表如下:偏移量 内容-8 32-bit 引用计数-4 32-bit 数组长度0.数组长度 * (元素尺寸) - 1 数组元素 元素尺寸=Sizeof(元素类型)根据上面的分配情况,可以得到如下结果:如果我们想要清空一个动态数组只需要把“数组长度”和“引用计数”清空即可。 ”引用上面的一句话就是:“权衡之下就有了折衷的办法,那就是定义的动态数组在必

12、要时转换为指针。 ”下面是清空动态数组的函数:procedure DynArraySetZero(var A);varP: PLongint; /占用 4 个字节,正好符合 32 位内存排列beginP := PLongint(A); / 指向 A 的地址Dec(P); /P 地址偏移量是 sizeof(A),指向了数组长度P := 0; / 长度清空Dec(P); / 指向引用计数P := 0; /计数清空。end;上面的函数就这么简单,而且效率也非常高。下面让我们再来看看怎样删除动态数组中的元素,函数体如下:*A 变量类型 , elSize = SizeOf(A) index 开始删除的位

13、置索引 ,Count 删除的数量*procedure DynArrayDelete(var A; elSize: Longint; index, Count: Integer);varlen, MaxDelete: Integer; P : PLongint; /4 个字节的长整形指针beginP := PLongint(A);/ 取的 A 的地址if P = nil thenExit;下面这句完全等同于 Dec(P) ; len := P 因为 Dec(P) = Pchar(P) 4 同样是移动 4 字节的偏移量,只不过后者按字节来移动 len := PLongint(PChar(P) -

14、4); / 变量的长度 ,偏移量 -4 if index = len then /要删除的位置超出范围,退出Exit;MaxDelete := len - index; / 最多删除的数量Count := Min(Count, MaxDelete); / 取得一个较小值if Count = 0 then / 不要求删除Exit; Dec(len, Count);/ 移动到要删除的位置 MoveMemory(PChar(P)+index*elSize , PChar(P)+(index + Count)*elSize , (len-index)*elSize); /移动内存Dec(P); /移出

15、 “数组长度”位置Dec(P); /移出“引用计数” 位置/重新再分配调整内存,len 新的长度. Sizeof(Longint) * 2 = 2*Dec(P)ReallocMem(P, len * elSize + Sizeof(Longint) * 2);Inc(P); / 指向数组长度P := len; / new lengthInc(P); / 指向数组元素,开始的位置PLongint(A) := P;end;对上面的例子,我们需要注意的是 elSize 参数 ,它必须是 SizeOf(DyArray_Name),表示元素所占用的字节数。 相信看了上面的例子后,对于动态数组的拷贝,移动想必也可以自己实现了吧 J后续:其实,Delphi 对许多类型的内存分配都很相似,比如 string 类型,其实它和动态数组是很相似的,我们完全可以把它拿来当成动态数组。实质上 string 是 Pchar 的简易版本。不管怎么说,了解一些内存的分配对我们这些开发人员来说还是有一些好处的。

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 行业资料 > 其它行业文档

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号