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!

4
  • Please replace TPointerArrayRec with PArrayRec, as this the standard convention for declaring pointer types. Commented Aug 19, 2011 at 10:09
  • 1
    FWIW, it is convention to name PArrayRec = ^TArrayRec, instead of TPointerArryRec. I would personally call them TRecArray and PRecArray, i.e. Array at the end. I see @iamjoosy had the same idea at almost the same time. Commented Aug 19, 2011 at 10:11
  • OK, but now I had to change that in my answer too. ;-) Commented Aug 19, 2011 at 10:55
  • Yep, let's all change our answers!.. Commented Aug 19, 2011 at 11:12

3 Answers 3

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.)

Sign up to request clarification or add additional context in comments.

2 Comments

+1 yes, you're right. I must get some sleep before asking 'silly' questions
@RBA - I don't think it's silly, using pointers may always be confusing. But sleep is good :)
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.

9 Comments

+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.
+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: Dentistry only occupies me during "office hours". And I don't hunt or play golf. <g> 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, 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).
> "I see several things that are suspicious" - Are you sure point (3) is suspicious?
|
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 ^.

4 Comments

+1, yes I know, but I want to understand the code in the actual form
I think deprecation should be dereference (or dereferencing)... Deprecation is marking something as deprecate (no longer used and in danger of being removed).
@Marjan whatever i said the operator ^ that is enough
@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'.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.