如何在Delphi中通过引用传递数组?

时间:2009-04-03 15:28:22

标签: delphi parameters reference types

我已经读过关于通过引用传递的内容

procedure test(var x:integer);
begin
  x:=x+5;
end;

所以上面的代码通过引用更新了5。我假设我是通过引用更新数组我可以声明 var X:blah的数组 ...有一些绑定的错误,只是想知道我是否应该使用指针的数据类型对于数据或者如果指针总是int ...只是所以我知道我是如何通过引用或我的代码中的其他东西进行传递的问题。

2 个答案:

答案 0 :(得分:24)

如果将动态数组作为非var参数传递,编译器将进行复制。

下面的小代码示例演示了如何在表单标题中显示37/42。

procedure IncArray1(data: array of integer);
var i : integer;
begin
  for i := Low(data) to High(data) do
    data[i] := data[i] + 5;
end;

procedure IncArray2(var data: array of integer);
var i : integer;
begin
  for i := Low(data) to High(data) do
    data[i] := data[i] + 5;
end;

procedure TForm8.FormCreate(Sender: TObject);
var
  data: array of integer;
begin
  SetLength(data, 1);
  data[0] := 37;
  IncArray1(data);
  Caption := IntToStr(data[0]);
  IncArray2(data);
  Caption := Caption + '/' + IntToStr(data[0]);
end;

如果我们查看生成的汇编代码,IncArray1以

开头
004552B4 8BCA             mov ecx,edx
004552B6 85C9             test ecx,ecx
004552B8 7807             js $004552c1
004552BA 8B1C88           mov ebx,[eax+ecx*4]
004552BD 49               dec ecx
004552BE 53               push ebx
004552BF 79F9             jns $004552ba
004552C1 8BC4             mov eax,esp

此代码将源数组复制到堆栈,并将eax设置为第一个元素的地址(=上次推送后存储在堆栈指针中的地址)。堆栈向下增长,因此代码从最后一个元素开始(edx在调用IncArray1时包含High(数据))并重复(读取元素; push元素;递减索引),直到它到达元素0。

IncArray2不包含此类代码。在调用IncArray2之前,调用者将数据的地址存储到eax寄存器中,而IncArray2只使用该地址。

如果您因任何原因不想使用'var',可以将数据地址传递给您的方法。但是,由于您无法在参数声明中使用语法'data:^ array of integer',因此您必须为数据声明一种类型。而且你必须在方法中的任何地方使用'data ^'而不是'data'。

type
  TData = array of integer;
  PData = ^TData;

procedure IncArray(data: PData);
var i : integer;
begin
  for i := Low(data^) to High(data^) do
    data^[i] := data^[i] + 5;
end;

procedure TForm8.FormCreate(Sender: TObject);
var
  data: TData;
begin
  SetLength(data, 2);
  data[0] := 37;
  IncArray(@data);
  Caption := IntToStr(data[0]);
end;

使用Delphi 2007进行测试。

答案 1 :(得分:6)

加布尔的答案是正确的,但关键点已经深入到底,我将把它作为一个单独的帖子出来:

首先定义您的类型!在这种特定情况下,编译器接受了一个整数数组,但这仅仅是因为它具有特殊含义,并且它是 NOT 你所期望的。在程序定义中定义类型的任何其他尝试都会失败。

与C不同,如果你想让两个东西分配兼容,你必须将它们声明为 SAME 类型,而不仅仅是构建相同的两种类型:

Var
     A : Array [1..4] of Integer;
     B : Array [1..4] of Integer;

Begin
    A := B;

不会编译。更确切地说:

Type
    Array4 = array [1..4] of Integer;

Var
    A : Array4;
    B : Array4;

Begin
    A := B;

并且编译器会执行您期望的操作。