• 设为首页
  • 点击收藏
  • 手机版
    手机扫一扫访问
    迪恩网络手机版
  • 关注官方公众号
    微信扫一扫关注
    公众号

Delphi中的动态数组总结

原作者: [db:作者] 来自: [db:来源] 收藏 邀请

今天做的一个项目中要使用一大串数据进行处理。如何对这一系列的数据进行保存成为一个首要的问题。唉,Delphi啊,你何时才能支持泛型啊。在C#,C++这都不是问题了啊。在Delphi里只有TStringList这个容器可以使用,但是它是处理字符串的。一进一出,需要大量的typecast时间。用链表??不值得。上网一查,呵呵,可以用动态数组。看来我还是一个新手,这个东西我都不知道啊。啥时候Delphi有了这个玩意了。

var

  i:array of integer;

begin

SetLength(i,length);//设置动态数组的长度

以后就可以像正常数组那样操作

有了动态数组就可以随时设置数组的大小,不会像以前那样事先定义数组的大小,对资源造成浪费。

动态数组的本质还是指针,上面的例子。i 就是一个指针类型。可以将两个动态数组之间进行引用赋值,当然了我们也可以将其复制给一个Pointer,只不过意义不大罢了。

var

p:Pointer;

i,j:Array of integer;

begin

SetLength(i,20);//分配内存空间

i[0] := 22;

i := j;//此时,i,j都同时指向了那段动态数组的存

p := i; //没有实际意义,只是证明了i 是指针类型

//释放工作

end;

使用完了内存当然需要释放了,否则会造成内存泄露。动态数组使用了 reference-counting 技术,所以在使用完后,只需将其赋值为nil即可。

-------------------------------------------------------------------

自从有了动态数组,链表除了在教科书里出现外,已经很少在实际编程中被使用了,事实也是如此,数组的确比传统链表快得多,而且也方便的多。
   从 Delphi4起,开始了内建各种类型的动态数组支持。但是,对我们来说动态数组支持似乎做的不够彻底,因为Delphi竟然连删除、插入、移动连续元素的函数都没有提供,让人使用起来总觉得不够爽!!! J 。作为一名程序员,我们当然要有自己解决问题的能力,下面就让我们简单介绍一下Delphi 下的动态数组。
  在Delphi中,数组类型有静态数组(a : array[0..1024] of integer)、动态数组(var a : array of integer)、指针数组(即指向静态数组的指针)和开放数组(仅用于参数传递)。静态数组、指针数组有速度快的好处,动态数组有大小可变的优势,权衡之下就有了折衷的办法,那就是定义的动态数组在必要时转换为指针。
  动态数组声明之后,只有下面几个函数可供操作:
  1. 设置数组大小,可以任意缩减或增加数组大小
  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修饰的动态数组会被作为形参传递,而动态数组用const修饰并不意味着你不能修改数组里的元素(不信你可以字自己在程序中试试。还有一点是High函数调用了Length 函数,所以我们在获取数组上限时最好直接用 Length(s) 函数。
  动态数组在内存空间中占用4个字节. 动态数组在内存中的分配表如下:
  偏移量 内容
  -8 32-bit 引用计数
  -4 32-bit 数组长度
  0..数组长度 * (元素尺寸) - 1 数组元素 元素尺寸=Sizeof(元素类型)
  根据上面的分配情况,可以得到如下结果:
  如果我们想要清空一个动态数组只需要把“数组长度”和“引用计数”清空即可。”引用上面的一句话就是:“权衡之下就有了折衷的办法,那就是定义的动态数组在必要时转换为指针。”下面是清空动态数组的函数:
  procedure DynArraySetZero(var A);
  var
   P: PLongint; //占用4个字节,正好符合 32 位内存排列
  begin
   P := PLongint(A); // 指向 A 的地址
   Dec(P); //P 地址偏移量是 sizeof(A),指向了数组长度
   P^ := 0; // 长度清空
   Dec(P); // 指向引用计数
   P^ := 0; //计数清空。
  end;
  上面的函数就这么简单,而且效率也非常高。
  下面让我们再来看看怎样删除动态数组中的元素,函数体如下:
  {************************************
  A 变量类型 , elSize = SizeOf(A)
  index 开始删除的位置索引 ,Count 删除的数量
  ****************************************}
  procedure DynArrayDelete(var A; elSize: Longint; index, Count: Integer);
  var
   len, MaxDelete: Integer;
   P : PLongint; //4 个字节的长整形指针
  begin
   P := PLongint(A);// 取的 A 的地址
   if P = nil then
   Exit;
   {
  下面这句完全等同于 Dec(P) ; len := P^ 因为 Dec(P) = Pchar(P) – 4 同样是移动4 字节的偏移量,只不过后者按字节来移动 }
  len := PLongint(PChar(P) - 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); //移出 “数组长度”位置
   Dec(P); //移出“引用计数” 位置
   //重新再分配调整内存,len 新的长度. Sizeof(Longint) * 2 = 2*Dec(P)
   ReallocMem(P, len * elSize + Sizeof(Longint) * 2);
   Inc(P); // 指向数组长度
   P^ := len; // new length
   Inc(P); // 指向数组元素,开始的位置
   PLongint(A) := P;
  end;
  对上面的例子,我们需要注意的是 elSize 参数 ,它必须是 SizeOf(DyArray_Name),表示元素所占用的字节数。
   相信看了上面的例子后,对于动态数组的拷贝,移动想必也可以自己实现了吧 J
  后续:
   其实,Delphi 对许多类型的内存分配都很相似,比如 string 类型,其实它和动态数组是很相似的,我们完全可以把它拿来当成动态数组。实质上 string 是 Pchar 的简易版本。不管怎么说,了解一些内存的分配对我们这些开发人员来说还是有一些好处的。


鲜花

握手

雷人

路过

鸡蛋
该文章已有0人参与评论

请发表评论

全部评论

专题导读
上一篇:
matlab学习笔记第七章——常微分方程(ODE)的数值解发布时间:2022-07-18
下一篇:
ode45求解微分方程(MATLAB)发布时间:2022-07-18
热门推荐
阅读排行榜

扫描微信二维码

查看手机版网站

随时了解更新最新资讯

139-2527-9053

在线客服(服务时间 9:00~18:00)

在线QQ客服
地址:深圳市南山区西丽大学城创智工业园
电邮:jeky_zhao#qq.com
移动电话:139-2527-9053

Powered by 互联科技 X3.4© 2001-2213 极客世界.|Sitemap