I already read up about passing by reference and so
procedure test(var x:integer);
begin
x:=x+5;
end;
so the above code updates 5 by reference. I assumed if I was updating an array by reference I could declare var X: array of blah... having some bound bugs and just wanted to know if I should be using the type of data for the pointer to the data or if the pointer is always int... just so I know if it's how I'm doing my passing by reference or something else in my code that is the issue.
And you'd have to use 'data^' instead of 'data' everywhere in the method. 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.
In Delphi to pass by reference you explicitly add the var keyword: procedure myFunc(var mytext:String); This means that myFunc can modify the contents of the string and have the caller see the changes.
Arrays can be passed by reference OR by degrading to a pointer. For example, using char arr[1]; foo(char arr[]). , arr degrades to a pointer; while using char arr[1]; foo(char (&arr)[1]) , arr is passed as a reference. It's notable that the former form is often regarded as ill-formed since the dimension is lost.
If we pass the address of an array while calling a function, then this is called function call by reference. The function declaration should have a pointer as a parameter to receive the passed address, when we pass an address as an argument.
If you pass dynamic array as a non-var parameter, compiler will make a copy.
The small code sample below demonstrates that by displaying 37/42 in the form caption.
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;
If we look into the generated assembler code, IncArray1 starts with
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
This code copies source array to the stack and sets eax to the address of the first element (= address stored in the stack pointer after last push). Stack grows down so the code starts with the last element (edx contains High(data) when IncArray1 is called) and repeats (read element; push element; decrement index) until it gets to the element 0.
IncArray2 contains no such code. Caller stores the address of the data into the eax register before calling IncArray2 and IncArray2 just uses this address.
In case you don't want to use 'var' for any reason, you can pass an address of the data to your method. But as you can't use syntax 'data: ^array of integer' in parameter declaration, you'd have to declare a type for your data. And you'd have to use 'data^' instead of 'data' everywhere in the method.
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;
Tested with Delphi 2007.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With