Delphi数组的使用

在 Delphi中,数组类型有静态数组(a : array[0..1024] of integer)、动态数组(var a : array of integer)、指针数组(即指向静态数组的指针)和开放数组(仅用于参数传递)。

静态数组、指针数组有速度快的好处,

动态数组有大小可变的优势,权衡 之下就有了折衷的办法,那就是定义的动态数组在必要时转换为指针。

动态数组声明之后,只有下面几个函数可供操作:

1.<wbr>设置数组大小,可以任意缩减或增加数组大小</wbr>

Procedure SetLength(var S ; NewLength : integer);

2.<wbr>取出连续元素,复制给另一个数组变量</wbr>

Function Copy(s;Index,Count : integer) : array ;

3.<wbr>取得数组大小及上下限</wbr>

Function Length(s):integer;

Function High(x):integer;

Function Low(x):integer;

值得注意的是,不加const或var修饰的动态数组会被作为形参传递,而动态数组用const修饰意味着你不能修改数组里的元素。

还有一点是High函数调用了Length 函数,所以我们在获取数组上最好直接用 Length(s) 函数。

动态数组在内存空间中占用4个字节.<wbr><wbr> 动态数组在内存中的分配表如下:</wbr></wbr>

偏移量<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> 内容</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

-8<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> 32-bit 引用计数</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

-4<wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr><wbr> 32-bit 数组长度</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

0..数组长度 * (元素尺寸) - 1<wbr>数组元素<wbr><wbr><wbr> 元素尺寸=Sizeof(元素类型)</wbr></wbr></wbr></wbr>

根据上面的分配情况,可以得到如下结果:

如果我们想要清空一个动态数组只需要把“数组长度”和“引用计数”清空即可。”引用上面的一句话就是:“权衡之下就有了折衷的办法,那就是定义的动态数组在必要时转换为指针。”下面是清空动态数组的函数:

procedure DynArraySetZero(var A);

var

<wbr>P: PLongint; //占用4个字节,正好符合 32 位内存排列</wbr>

begin

<wbr>P := PLongint(A); // 指向 A 的地址</wbr>

<wbr>Dec(P); //P 地址偏移量是 sizeof(A),指向了数组长度</wbr>

<wbr>P^ := 0; // 长度清空</wbr>

<wbr>Dec(P); // 指向引用计数</wbr>

<wbr>P^ := 0; //计数清空。</wbr>

end;

上面的函数就这么简单,而且效率也非常高。

下面让我们再来看看怎样删除动态数组中的元素,函数体如下:

{ A 变量类型<wbr>, elSize = SizeOf(A),index 开始删除的位置索引 ,Count 删除的数量}</wbr>

procedure DynArrayDelete(var A; elSize: Longint; index, Count: Integer);

var

<wbr>len, MaxDelete: Integer;</wbr>

<wbr>P : PLongint; //4 个字节的长整形指针</wbr>

begin

<wbr>P := PLongint(A);// 取的 A 的地址</wbr>

<wbr>if P = nil then</wbr>

<wbr><wbr><wbr> Exit;</wbr></wbr></wbr>

<wbr>{</wbr>

{下面这句完全等同于 Dec(P) ; len := P^<wbr>因为 Dec(P) = Pchar(P) – 4<wbr>同样是移动4 字节的偏移量,只不过后者按字节来移动 }</wbr></wbr>

len := PLongint(PChar(P) - 4)^; // 变量的长度 ,偏移量 -4

<wbr>if index &gt;= len then //要删除的位置超出范围,退出</wbr>

<wbr><wbr><wbr> Exit;</wbr></wbr></wbr>

<wbr>MaxDelete := len - index; // 最多删除的数量</wbr>

<wbr>Count := Min(Count, MaxDelete); // 取得一个较小值</wbr>

<wbr>if Count = 0 then // 不要求删除</wbr>

<wbr><wbr><wbr> Exit;</wbr></wbr></wbr>

Dec(len, Count);// 移动到要删除的位置

<wbr>MoveMemory(<wbr><wbr><wbr><wbr><wbr><wbr><wbr> PChar(P)+index*elSize , PChar(P)+(index + Count)*elSize , (len-index)*elSize); //移动内存</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

<wbr>Dec(P);<wbr>//移出 “数组长度”位置</wbr></wbr>

<wbr>Dec(P);<wbr>//移出“引用计数” 位置</wbr></wbr>

<wbr>//重新再分配调整内存,len 新的长度. Sizeof(Longint) * 2 = 2*Dec(P)</wbr>

<wbr>ReallocMem(P, len * elSize + Sizeof(Longint) * 2);</wbr>

<wbr>Inc(P); // 指向数组长度</wbr>

<wbr>P^ := len; // new length</wbr>

<wbr>Inc(P); // 指向数组元素,开始的位置</wbr>

<wbr>PLongint(A) := P;</wbr>

end;

<wbr></wbr>

对上面的例子,我们需要注意的是 elSize 参数 ,它必须是 SizeOf(DyArray_Name),表示元素所占用的字节数。

看了上面的例子后,对于动态数组的拷贝,移动也可以自己实现了

<wbr><wbr><wbr> 其实,Delphi 对许多类型的内存分配都很相似,比如 string 类型,其实它和动态数组是很相似的,我们完全可以把它拿来当成动态数组。实质上 string 是 Pchar 的简易版本。不管怎么说,了解一些内存的分配对我们这些开发人员来说还是有一些好处的。</wbr></wbr></wbr>


1、动态数组是指针吗?
动态数组通常会表现出指针功能,先看下面的例子:
procedure DymArrTest();
var
<wbr> A, B: array of Integer;<br style="line-height: 22px;"> begin<br style="line-height: 22px;"><wbr> SetLength(A, 3);<br style="line-height: 22px;"><wbr> A[0] := 0;<br style="line-height: 22px;"><wbr> B := A;<br style="line-height: 22px;"><wbr> B[0] := 1;<br style="line-height: 22px;"><wbr> ShowMessage(IntToStr(A[0]));<br style="line-height: 22px;"> end;<br style="line-height: 22px;"> 在以上程序中,A、B数组指向的是相同的地址,所以改变了B[0],结果A[0]会等于1。<br style="line-height: 22px;"> 虽然动态数组暗含指针功能,但它的内存管理却是生存期管理类型,无需手工释放。</wbr></wbr></wbr></wbr></wbr></wbr>

2、为什么改变形参却没有改变实参的值?
虽然动态数组会表现出指针的功能,在直接用它声明形参,改变形参值时,却是不会改变实参的,看下面的例子:
procedure DymArrParam(Arr: array of Integer);
var
<wbr> I: Integer;<br style="line-height: 22px;"> begin<br style="line-height: 22px;"><wbr> for I := 0 to Length(Arr) - 1 do<wbr><br style="line-height: 22px;"><wbr><wbr><wbr> Arr[I] := 2;<br style="line-height: 22px;"> end;</wbr></wbr></wbr></wbr></wbr></wbr>

procedure TForm1.Button1Click(Sender: TObject);
var
<wbr> A:<wbr> array of Integer;<br style="line-height: 22px;"><wbr> I: Integer;<br style="line-height: 22px;"> begin<br style="line-height: 22px;"><wbr> SetLength(A, 2);<br style="line-height: 22px;"><wbr> for I := 0 to Length(A)-1 do<wbr><wbr><wbr><wbr><span style="line-height: 22px; color: rgb(0, 0, 255);">//此处一定要是length(a)-1 而不能是length(a),原文是错的,运行时总出现莫名其妙的指针类错 误,不得其解,后来在网上查找资料时,猛然发现了这个错误,一试,竟然就是调试中出现的全部错误的根源,真是发人深省啊,有时一个看似很复杂的错误,其实是很简单的一个甚至是不经意的小错误造成的.就是这个-1让我找个一个下午,过总算找到了错误的源头.网上的源程序,如果是自己写出来的倒不容易出错了,直接复制才会出这种错,找起来还真不好找.</span><br style="line-height: 22px;"><wbr><wbr><wbr> A[I] := 1;<br style="line-height: 22px;"><wbr> DymArrParam(A);//试图把数组中的元素值改变为2<br style="line-height: 22px;"><wbr> Caption := IntToStr(A[0]) + ',' + IntToStr(A[1]);<br style="line-height: 22px;"> end;<br style="line-height: 22px;"> 可以看到最终并没有把实参数组A元素值变为2。<br style="line-height: 22px;"> 原因是这种传递方法编译器会在DymArrParam中复制了一个A的副本,而不是像在第1点中所期望的那样改变了A的值,可见动态数组并非就等同指针。</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

3、如何通过动态数组的形参改变实参值?
<wbr><wbr> 1&gt;var<br style="line-height: 22px;"> 在Delphi中很显然方法的是,在DymArrParam过程中通过var修饰形参,即<br style="line-height: 22px;"> procedure DymArrParam(var Arr: array of Integer);<br style="line-height: 22px;"> 在不想通过形参改变实参值时,可以用const修饰形参,明确表示出不可修改意思,即<br style="line-height: 22px;"> procedure DymArrParam(const Arr: array of Integer);<br style="line-height: 22px;"> 这样做之后,如果对Arr赋值的话,将会编译不通过。<br style="line-height: 22px;"><wbr><wbr> 2&gt;type<br style="line-height: 22px;"> 另一种就是用type重新定义一个类型,<br style="line-height: 22px;"> 例如:<br style="line-height: 22px;"> type<br style="line-height: 22px;"><wbr> TDymIntArray = array of Integer;//在system单元已经声明了个TBoundArray,用它也可以<br style="line-height: 22px;"> 然后用于形参声明,如下:<br style="line-height: 22px;"> procedure DymArrParam(Arr: TDymIntArray);<br style="line-height: 22px;"> 调用此函数时用的实参的类型也必须为TDymIntArray。<br style="line-height: 22px;"> 这样做,不用var修饰形参,也一样可以通过形参改变实参。在这种情况下,即使用const修饰形参,也一样可以修改形参的值来改变实参的值。</wbr></wbr></wbr></wbr></wbr>

4.一个控件数组的实现:
procedure TForm1.BitBtn2Click(Sender: TObject);
var
<wbr><wbr> png:array [1..5] of TPNGObject;<br style="line-height: 22px;"><wbr><wbr> img:array [1..5] of TImage;<br style="line-height: 22px;"><wbr><wbr> i:Integer;<br style="line-height: 22px;"> begin<br style="line-height: 22px;"><wbr><wbr> img[1]:=Image1;<br style="line-height: 22px;"><wbr><wbr> img[2]:=Image2;<br style="line-height: 22px;"><wbr><wbr> img[3]:=Image3;<br style="line-height: 22px;"><wbr><wbr> img[4]:=Image4;<br style="line-height: 22px;"><wbr><wbr> img[5]:=Image5;<br style="line-height: 22px;"> for i:=1 to 5 do<br style="line-height: 22px;"> begin<br style="line-height: 22px;"><wbr><wbr> png[i]:=TPNGObject.Create;<br style="line-height: 22px;"><wbr><wbr> png[i].LoadFromFile('./002.png');<br style="line-height: 22px;"><wbr><wbr> img[i].Picture.Assign(png[1]);<br style="line-height: 22px;"> end;<br style="line-height: 22px;"> end;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

5.将动态数组作为函数或过程的一个参数。
procedure ListView(var myArr : array of string);
var<wbr><br style="line-height: 22px;"> i :integer;<br style="line-height: 22px;"> mytext :string;<br style="line-height: 22px;"> begin<br style="line-height: 22px;"> setlength(myArr,10);<br style="line-height: 22px;"><wbr><wbr> for i :=3 to 9 do<wbr><br style="line-height: 22px;"> myarr[i] := inttostr(i);<br style="line-height: 22px;"> for i :=0 to 9 do<br style="line-height: 22px;"> mytext :=mytext + myarr[i]<wbr><wbr> ;<br style="line-height: 22px;"> end;</wbr></wbr></wbr></wbr></wbr></wbr>

procedure makeA(name,id:string);
var
<wbr><wbr><wbr><wbr> Darr :array of string;<br style="line-height: 22px;"> i :integer;<br style="line-height: 22px;"> begin<br style="line-height: 22px;"><wbr><wbr> setlength(Darr,4);<br style="line-height: 22px;"> for i := 0 to 3 do<br style="line-height: 22px;"><wbr><wbr><wbr><wbr> Darr[i] := inttostr(i);<br style="line-height: 22px;"> end;<br style="line-height: 22px;"> Listview(Darr);<br style="line-height: 22px;"> end;<br style="line-height: 22px;"><wbr><wbr><wbr> 如上的一段代码在delphi里不能通过语法检查,会在‘setlength(myarr,10)‘处报错。delphi会报告语法错误 --incompatible type。产生这样的错误原因 直接在参数中写<wbr><wbr> array<wbr><wbr> of<wbr><wbr> string,编译器不会认为它是动态数组,而认为它是静态数组,而静态数组是不能执行setLength操作的。这是历史遗留问题,PASCAL没有动 态数组,只有静态数组,为了向过程传递各种长度的静态数组,于是规定静态数组参数类型可以写成<wbr><wbr> array<wbr><wbr> of<wbr><wbr> integer这样的形式,省去了标界,以便接收不同长度的数组作参数。Delphi支持动态数组,但在过程参数中,array<wbr><wbr> of<wbr><wbr> integer这样的定义形式已经认为是静态数组类型。所以必须以自定义类型的方式来实现动态数组作过程参数。<wbr><br style="line-height: 22px;"> 要想实现上段代码的原本思想,则需要在单元的变量定义部分,自定义一个动态数组的变量类型,如:<br style="line-height: 22px;"> type<wbr><br style="line-height: 22px;"> TDyArr = array of string;<br style="line-height: 22px;"> 上段代码改为:<br style="line-height: 22px;"> procedure ListView(var myArr : TDyArr);<br style="line-height: 22px;"> var<wbr><br style="line-height: 22px;"> i :integer;<br style="line-height: 22px;"> mytext :string;<br style="line-height: 22px;"> begin<br style="line-height: 22px;"> setlength(myArr,10);<br style="line-height: 22px;"><wbr><wbr> for i :=3 to 9 do<wbr><br style="line-height: 22px;"> myarr[i] := inttostr(i);<br style="line-height: 22px;"> for i :=0 to 9 do<br style="line-height: 22px;"> mytext :=mytext + myarr[i]<wbr><wbr> ;<br style="line-height: 22px;"> end;</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

procedure makeA(name,id:string);
var
<wbr><wbr><wbr><wbr> Darr :TDyArr;<br style="line-height: 22px;"> i :integer;<br style="line-height: 22px;"> begin<br style="line-height: 22px;"><wbr><wbr> setlength(Darr,4);<br style="line-height: 22px;"> for i := 0 to 3 do<br style="line-height: 22px;"><wbr><wbr><wbr><wbr> Darr[i] := inttostr(i);<br style="line-height: 22px;"> end;<br style="line-height: 22px;"> Listview(Darr);<br style="line-height: 22px;"> end;<br style="line-height: 22px;"> 就不会出现语法错误的报告了。</wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr></wbr>

6.取多维数组的边界

在delphi中数组不以某个固定数为基准,可以用High()和 Low()来取其上下边界。<wbr><br style="line-height: 28px;"> 对于二维数组我们可以用以下的方法取其边界:<wbr><br style="line-height: 28px;"> a :Array[1..9,2..8] of integer;<wbr><br style="line-height: 28px;"><br style="line-height: 28px;"> 1、High(a)<wbr><br style="line-height: 28px;"> Low(a)<wbr><br style="line-height: 28px;"><br style="line-height: 28px;"> 2、High(a[Low(a)] )<br style="line-height: 28px;"> Low(a[Low(a)])</wbr></wbr></wbr></wbr></wbr>


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Delphi 中的数组子集可以通过数组的索引范围来实现。你可以使用以下代码来创建一个数组的子集: ```delphi type TMyArray = array of Integer; procedure CreateSubset(const SourceArray: TMyArray; StartIndex, EndIndex: Integer; var Subset: TMyArray); var i, SubsetLength: Integer; begin SubsetLength := EndIndex - StartIndex + 1; SetLength(Subset, SubsetLength); for i := StartIndex to EndIndex do Subset[i - StartIndex] := SourceArray[i]; end; var MyArray, MySubset: TMyArray; begin // 创建原始数组 SetLength(MyArray, 5); MyArray[0] := 10; MyArray[1] := 20; MyArray[2] := 30; MyArray[3] := 40; MyArray[4] := 50; // 创建子集,从索引1到索引3的元素 CreateSubset(MyArray, 1, 3, MySubset); // 输出子集元素 for i := 0 to High(MySubset) do WriteLn(MySubset[i]); end. ``` 在上面的示例中,我们首先定义了一个 `TMyArray` 类型作为数组的别名。然后,我们创建了一个名为 `CreateSubset` 的过程,它接受一个源数组、起始索引和结束索引,并通过引用参数返回子集数组。在这个过程中,我们使用 `SetLength` 函数为子集数组分配内存,并使用一个循环将源数组中指定索引范围内的元素复制到子集数组中。最后,我们使用 `WriteLn` 函数输出子集数组的元素。 在主程序中,我们创建了一个原始数组 `MyArray`,并初始化了一些元素。然后,我们调用 `CreateSubset` 过程来创建一个从索引1到索引3的子集数组 `MySubset`。最后,我们使用一个循环在控制台上输出子集数组的元素。 希望这个示例能够帮助你理解如何在 Delphi 中创建数组的子集。如果你有任何进一步的问题,请随时提问!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值