1

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?

1 Answer 1

2

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;
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks @Andreas...ive been playing with all those ways to do it and I was trying to work out if one way was better than the other or if one gave a pointer to pointer situation, but it seems that they all give the same result and it doesn't matter what happens to the original pointer.
@WartH0g: Correct, as you can see by the last tests, all four pointers point to the exact same location in memory, namely, the Details member of the second TMsgData value in the dynamic array.
Thats largely the bit I was missing - how to see the actual address so I could verify they are all pointing to the same thing. Your code is very useful, i’ve saved it for future reference.

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.