WartH0g
WartH0g

Reputation: 35

How do I assign a pointer to a record element using an existing pointer?

I understand the concept of pointers and how to use, but I just want to clear up a bit of confusion in my head about assigning a pointer to a record sub-element already pointed to by another pointer...

I've seen some questions elsewhere that are I think asking the same thing, but the answers are in C...

If I have:

type
  TDetails = record
     Name : string;
     Origin : string;
  end;

  TMsgData = record
     ID : string;
     Code : integer;
     Details : TDetails;
  end;

var
  MessageData = array of TMsgData;

I can obviously get a pointer to specific record of TMsgData type by:

var
  pMessageData = ^TMsgData;

begin
  pMessageData := @MessageData[0];
...

And of course I can then access all the record elements using that pointer with standard dereferencing.

But, how do I get a new pointer to just the Details record of MessageData[0] using the first pointer? I want to avoid having a pointer to a pointer so if pMessageData is free'd I still have the other pointer.

If I do

name := pMessageData.Details.Name;

then Delphi will automatically dereference this to give me the value of name. So if I did:

var
  pMessageDetails = ^TDetails;

begin
  pMessageDetails = @pMessageData.Details;

*or*

  pMessageDetails = Addr(pMessageData^.Details);

Do either of those give me a pointer to a pointer or a new pointer to the original record?

Upvotes: 1

Views: 627

Answers (1)

Andreas Rejbrand
Andreas Rejbrand

Reputation: 109003

Let's be pedantic.

pMessageData is a pointer to a TMsgData. This means that pMessageData^ is a TMsgData, and pMessageData^.Details is its TDetails.

A pointer to this record is therefore @(pMessageData^.Details), which can also be written Addr(pMessageData^.Details) using the Addr function.

Furthermore, @(pMessageData^.Details) is parsed the same way as @pMessageData^.Details, so you can omit the parentheses.

In fact, you can even omit the dereferencing operator and write simply @pMessageData.Details.


Actually, you can easily verify that my conclusions are correct using Delphi itself:

procedure TForm1.FormCreate(Sender: TObject);
var
  pMessageData: ^TMsgData;
  p1, p2, p3, p4: ^TDetails;
begin

  SetLength(MessageData, 3);

  MessageData[1].ID := 'Alpha';
  MessageData[1].Code := 123;
  MessageData[1].Details.Name := 'Test';
  MessageData[1].Details.Origin := 'NYC';

  pMessageData := @MessageData[1];

  p1 := @(pMessageData^.Details);
  p2 := Addr(pMessageData^.Details);
  p3 := @pMessageData^.Details;
  p4 := @pMessageData.Details;

  ShowMessage(p1^.Origin);
  ShowMessage(p2^.Origin);
  ShowMessage(p3^.Origin);
  ShowMessage(p4^.Origin);

  ShowMessage(NativeInt(p1).ToString);
  ShowMessage(NativeInt(p2).ToString);
  ShowMessage(NativeInt(p3).ToString);
  ShowMessage(NativeInt(p4).ToString);

  ShowMessage(NativeInt(@MessageData[1].Details).ToString); // same as last four

  ExitProcess(0)

end;

Upvotes: 2

Related Questions