在 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
-4
0..数组长度 * (元素尺寸) - 1
根据上面的分配情况,可以得到如下结果:
如果我们想要清空一个动态数组只需要把“数组长度”和“引用计数”清空即可。”引用上面的一句话就是:“权衡之下就有了折衷的办法,那就是定义的动态数组在必要时转换为指针。”下面是清空动态数组的函数:
procedure DynArraySetZero(var A);
var
begin
end;
上面的函数就这么简单,而且效率也非常高。
下面让我们再来看看怎样删除动态数组中的元素,函数体如下:
{ A 变量类型
procedure DynArrayDelete(var A; elSize: Longint; index, Count: Integer);
var
begin
{下面这句完全等同于 Dec(P) ; len := P^
len := PLongint(PChar(P) - 4)^; // 变量的长度 ,偏移量 -4
Dec(len, Count);// 移动到要删除的位置
end;
对上面的例子,我们需要注意的是 elSize 参数 ,它必须是 SizeOf(DyArray_Name),表示元素所占用的字节数。
看了上面的例子后,对于动态数组的拷贝,移动也可以自己实现了
1、动态数组是指针吗?
动态数组通常会表现出指针功能,先看下面的例子:
procedure DymArrTest();
var
begin
end;
在以上程序中,A、B数组指向的是相同的地址,所以改变了B[0],结果A[0]会等于1。
虽然动态数组暗含指针功能,但它的内存管理却是生存期管理类型,无需手工释放。
2、为什么改变形参却没有改变实参的值?
虽然动态数组会表现出指针的功能,在直接用它声明形参,改变形参值时,却是不会改变实参的,看下面的例子:
procedure DymArrParam(Arr: array of Integer);
var
begin
end;
procedure TForm1.Button1Click(Sender: TObject);
var
begin
end;
可以看到最终并没有把实参数组A元素值变为2。
原因是这种传递方法编译器会在DymArrParam中复制了一个A的副本,而不是像在第1点中所期望的那样改变了A的值,可见动态数组并非就等同指针。
3、如何通过动态数组的形参改变实参值?
在Delphi中很显然方法的是,在DymArrParam过程中通过var修饰形参,即
procedure DymArrParam(var Arr: array of Integer);
在不想通过形参改变实参值时,可以用const修饰形参,明确表示出不可修改意思,即
procedure DymArrParam(const Arr: array of Integer);
这样做之后,如果对Arr赋值的话,将会编译不通过。
另一种就是用type重新定义一个类型,
例如:
type
然后用于形参声明,如下:
procedure DymArrParam(Arr: TDymIntArray);
调用此函数时用的实参的类型也必须为TDymIntArray。
这样做,不用var修饰形参,也一样可以通过形参改变实参。在这种情况下,即使用const修饰形参,也一样可以修改形参的值来改变实参的值。
4.一个控件数组的实现:
procedure TForm1.BitBtn2Click(Sender: TObject);
var
begin
for i:=1 to 5 do
begin
end;
end;
5.将动态数组作为函数或过程的一个参数。
procedure ListView(var myArr : array of string);
var
i :integer;
mytext :string;
begin
setlength(myArr,10);
myarr[i] := inttostr(i);
for i :=0 to 9 do
mytext :=mytext + myarr[i]
end;
procedure makeA(name,id:string);
var
i :integer;
begin
for i := 0 to 3 do
end;
Listview(Darr);
end;
要想实现上段代码的原本思想,则需要在单元的变量定义部分,自定义一个动态数组的变量类型,如:
type
TDyArr = array of string;
上段代码改为:
procedure ListView(var myArr : TDyArr);
var
i :integer;
mytext :string;
begin
setlength(myArr,10);
myarr[i] := inttostr(i);
for i :=0 to 9 do
mytext :=mytext + myarr[i]
end;
procedure makeA(name,id:string);
var
i :integer;
begin
for i := 0 to 3 do
end;
Listview(Darr);
end;
就不会出现语法错误的报告了。
6.取多维数组的边界
在delphi中数组不以某个固定数为基准,可以用High()和 Low()来取其上下边界。
对于二维数组我们可以用以下的方法取其边界:
a :Array[1..9,2..8] of integer;
1、High(a)
Low(a)
2、High(a[Low(a)] )
Low(a[Low(a)])