3

I have the following code which is working, but I don't understand it 100% (please see the comments from code):

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TMyRec=record
    a:Integer;
    b:String;
  end;
  TRecArray=array of TMyRec;
  PRecArray = ^TRecArray;

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    { Private declarations }
  public
   v1:TRecArray;
   procedure Test(a:PRecArray);
    { Public declarations }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ TForm1 }

procedure TForm1.FormCreate(Sender: TObject);
begin
 SetLength(v1,3);
 v1[0].b:='test1';//set the first value
 Test(PRecArray(v1));//call method to change the value assigned before
end;

procedure TForm1.Test(a: PRecArray);
begin
 ShowMessage(v1[0].b);//shows test1
 try
  a^[0].b:='test2' //this is raising an error...
 except

 end;
 PRecArray(@a)^[0].b:='test3';//this is working...
 ShowMessage(v1[0].b);//shows test3
end;

end.

I don't understand why 'a^[0].b:='test2' is raising an error.

Thank you!

RBA
  • 12,337
  • 16
  • 79
  • 126

3 Answers3

10

Your 'Test' procedure expects a 'PRecArray', but you're passing a 'TRecArray' to it. Try calling it like

 Test(@v1);//call method to change the value assigned before

Typecasting a 'TRecArray' to a 'PRecArray' will not make it a 'PRecArray'. (Note: your 'test3' will fail then of course.)

Sertac Akyuz
  • 54,131
  • 4
  • 102
  • 169
4

I see several things that are suspicious.

1

There is hardly ever a need to take a pointer to a dynamic array, as dynamic array variables are already pointers (well, references).

To pass such an array to a function or procedure, use var parameters:

procedure TForm1.Test(var a: TRecArray);

Now you don't have to use pointer syntax to access the array:

a[0].b := 'test2';

2

You call Test with:

Test(PRecArray(v1));

In your original, Test took a PRecArray, but you are not passing one (you are passing a TRecArray), so you should have done:

Test(@v1); // or Test(Addr(v1));

Applying my change above, where Test has a var parameter, simply use:

Test(v1);

3

Ok, this is probably not suspicous, but I'd like to plug my article Addressing Pointers, about pointers for Delphi programmers. It explains many of the issues you seem to have.

Rudy Velthuis
  • 28,387
  • 5
  • 46
  • 94
  • +1 Rudy. yes, I know your article, which btw is very well done. Question was how that code is working. It wasn't wrote by me, and I didn't understand it. Thanks for the suggestions. – RBA Aug 19 '11 at 10:29
  • +1 Shameless plug been bookmarked a long, long time ago. Congrats by the way on picking up rep fast. At this rate you'll join David, Andreas a.o very soon. :-) See you are into (Objective-) C as well. Can't figure out where you find the time. Or does dentistry no longer occupy you full time? – Marjan Venema Aug 19 '11 at 10:33
  • @Marjan: Dentistry only occupies me during "office hours". And I don't hunt or play golf. I got a Mac a few months ago and am now trying to get acquainted with Cocoa and Objective-C. And interesting language, but no Delphi. I can hardly wait for XE2. – Rudy Velthuis Aug 19 '11 at 10:45
  • @Rudy, ah yes, no hunting or golfing does save a lot of time :-)) Waiting for XE here too, especially 64 bit (work), but the x-platform as well (personal projects). – Marjan Venema Aug 19 '11 at 10:51
  • > *"I see several things that are suspicious"* - Are you sure point (3) is suspicious? – Sertac Akyuz Aug 19 '11 at 11:13
  • @Sertac: LOL! No, not really. But it is not up to me to judge that. – Rudy Velthuis Aug 19 '11 at 11:25
  • @Rudy - I've seen it referred countless times, read it myself a few times.. no suspicion there :) – Sertac Akyuz Aug 19 '11 at 11:53
  • @Sertac: phew! I', relieved. – Rudy Velthuis Aug 19 '11 at 13:09
  • Hmmm... apparently someone doesn't like me plugging my articles. I got a downvote on two answers where I refer to my articles for further reading. This is one of them. – Rudy Velthuis Aug 21 '11 at 18:57
1

You could replace the

procedure TForm1.Test(a: TPointerArrayRec);

with

   procedure TForm1.Test(var a: TArrayRec);   

it's simpler and you don't have to use the deprecation dereference operator ^.

Ken White
  • 123,280
  • 14
  • 225
  • 444
opc0de
  • 11,557
  • 14
  • 94
  • 187
  • +1, yes I know, but I want to understand the code in the actual form – RBA Aug 19 '11 at 10:01
  • I think deprecation should be dereference (or dereferencing)... Deprecation is marking something as deprecate (no longer used and in danger of being removed). – Marjan Venema Aug 19 '11 at 10:28
  • @Marjan whatever i said the operator ^ that is enough – opc0de Aug 19 '11 at 11:56
  • @opc0de: No, it's not. Marjan is correct, and you should have edited your post to correct your mistake. Unless calling you 'oopscode' would be close enough, since it starts with 'o' and ends in 'de'. – Ken White Aug 19 '11 at 23:29