zoukankan      html  css  js  c++  java
  • Delphi动态数组介绍

    Delphi动态数组介绍(http://blog.csdn.net/chenyq2008/article/details/2986983)

     从 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 的简易版本。不管怎么说,了解一些内存的分配对我们这些开发人员来说还是有一些好处的。

  • 相关阅读:
    bzoj 4237 稻草人
    bzoj 4537 最小公倍数
    POJ 2763 Housewife Wind(树链剖分)(线段树单点修改)
    HDU 3966 Aragorn's Story(树链剖分)(线段树区间修改)
    spoj 913 Query on a tree II (倍增lca)
    spoj 375 Query on a tree (树链剖分)
    hiho一下第133周 2-SAT·hihoCoder音乐节(2-SAT)(强连通)
    hiho一下第131周 后缀自动机二·重复旋律8(循环相似子串)
    hiho一下第130周 后缀自动机二·重复旋律7
    hiho一下第129周 后缀自动机二·重复旋律6
  • 原文地址:https://www.cnblogs.com/luckForever/p/7255108.html
Copyright © 2011-2022 走看看