Pointers in Delphi
Pointers in Delphi
Pointers are a special type of variable. Like a meta-variable. They can point to other variables, or to memory. You might use a record pointer, for example, to point to a block of memory where you have stored lots of record data. You would then use the pointer just as if it were a record variable. The Pointer type provides a general use pointer to any memory based variable. That is, one that is accessed by reference.
Delphi provides a number of typed pointer types, such as PChar, and PExtended, along with a generic, 'point to anything' type - the Pointer type.
var
generalPtr : Pointer; // A pointer to anything
formPtr : ^TForm; // A pointer to a form object
begin
// The current unit's form is addressable via the self keyword
generalPtr := Addr(self);
// We can assign this pointer to the form pointer
formPtr := generalPtr;
// And set the form caption to show this
formPtr.Caption := 'Test program';
end;
The nice thing about the typed pointers is that they work sensibly with the Inc and Dec functions. Incrementing an PInt64 pointer will add SizeOf(Int64) bytes to the pointer address so that it points to the next Int64 variable in memory.
The Pointer type is a dangerous one - it falls foul of Delphi's normally tight type handling. Use it with care, or you will end up addressing the wrong memory. It is normally always better to use a specific pointer reference to the data type you are using.
Different Pointer types in Delphi
PAnsiChar: A pointer to an AnsiChar value
PAnsiString: Pointer to an AnsiString value
PChar: A pointer to an Char value
PCurrency: Pointer to a Currency value
PDateTime: Pointer to a TDateTime value
PExtended: Pointer to a Extended floating point value
PInt64: Pointer to an Int64 value
PShortString: A pointer to an ShortString value
PString: Pointer to a String value
PVariant: Pointer to a Variant value
PWideChar: Pointer to a WideChar
PWideString: Pointer to a WideString value
A simple example using PChar
The PChar type can be used to scan along a string :
var
myString : string;
myCharPtr : PChar;
i : Integer;
begin
// Create a string of Char's
myString := 'Hello World';
// Point to the first character in the string
i := 1;
myCharPtr := Addr(myString[i]);
// Display all characters in the string
while i <= Length(myString) do
begin
ShowMessage(myCharPtr^); // Display the string characters one by one
Inc(i);
Inc(myCharPtr);
end;
end;
There are two things to note here. First the use of Addr function to get the address of the string. You could equally use the @ operator. Pointers always work with addresses - the address of a variable here, or a block of acquired memory. Here we point the PChar value to the first character in the string.
Secondly, now that we have a pointer, we use the ^ character at the end of the pointer name to refer to what the pointer points to. In this case, a character.
A PChar^ will always give us a character. A PInt64^, for example, will give us an Int64 value. This is where the typing comes in.
Record pointers
You can define a pointer to any data type using a different technique:
var
myRecordPtr : ^TMyRecord;
Here, the ^ symbol is used to dereference the type - we are saying that we do not have a TMyRecord type, but a pointer to one. Note that this is a prefix use of ^.
Let us create a full record example :
type
TMyRecord = Record
name : String[20];
age : Integer;
end;
var
myRecord : TMyRecord;
myRecordPtr : ^TMyRecord;
begin
myRecord.name := 'Fred Bloggs';
myRecord.age := 23;
myRecordPtr := @myRecord;
ShowMessage(myRecordptr.name); // Displays 'Fred Bloggs'
end;
When we simply refer to the record field name, without a ^, Delphi is in fact adding one for us - it recognises what we are doing, and helps us make for more readable code.
Pointers are a special type of variable. Like a meta-variable. They can point to other variables, or to memory. You might use a record pointer, for example, to point to a block of memory where you have stored lots of record data. You would then use the pointer just as if it were a record variable. The Pointer type provides a general use pointer to any memory based variable. That is, one that is accessed by reference.
Delphi provides a number of typed pointer types, such as PChar, and PExtended, along with a generic, 'point to anything' type - the Pointer type.
var
generalPtr : Pointer; // A pointer to anything
formPtr : ^TForm; // A pointer to a form object
begin
// The current unit's form is addressable via the self keyword
generalPtr := Addr(self);
// We can assign this pointer to the form pointer
formPtr := generalPtr;
// And set the form caption to show this
formPtr.Caption := 'Test program';
end;
The nice thing about the typed pointers is that they work sensibly with the Inc and Dec functions. Incrementing an PInt64 pointer will add SizeOf(Int64) bytes to the pointer address so that it points to the next Int64 variable in memory.
The Pointer type is a dangerous one - it falls foul of Delphi's normally tight type handling. Use it with care, or you will end up addressing the wrong memory. It is normally always better to use a specific pointer reference to the data type you are using.
Different Pointer types in Delphi
PAnsiChar: A pointer to an AnsiChar value
PAnsiString: Pointer to an AnsiString value
PChar: A pointer to an Char value
PCurrency: Pointer to a Currency value
PDateTime: Pointer to a TDateTime value
PExtended: Pointer to a Extended floating point value
PInt64: Pointer to an Int64 value
PShortString: A pointer to an ShortString value
PString: Pointer to a String value
PVariant: Pointer to a Variant value
PWideChar: Pointer to a WideChar
PWideString: Pointer to a WideString value
A simple example using PChar
The PChar type can be used to scan along a string :
var
myString : string;
myCharPtr : PChar;
i : Integer;
begin
// Create a string of Char's
myString := 'Hello World';
// Point to the first character in the string
i := 1;
myCharPtr := Addr(myString[i]);
// Display all characters in the string
while i <= Length(myString) do
begin
ShowMessage(myCharPtr^); // Display the string characters one by one
Inc(i);
Inc(myCharPtr);
end;
end;
There are two things to note here. First the use of Addr function to get the address of the string. You could equally use the @ operator. Pointers always work with addresses - the address of a variable here, or a block of acquired memory. Here we point the PChar value to the first character in the string.
Secondly, now that we have a pointer, we use the ^ character at the end of the pointer name to refer to what the pointer points to. In this case, a character.
A PChar^ will always give us a character. A PInt64^, for example, will give us an Int64 value. This is where the typing comes in.
Record pointers
You can define a pointer to any data type using a different technique:
var
myRecordPtr : ^TMyRecord;
Here, the ^ symbol is used to dereference the type - we are saying that we do not have a TMyRecord type, but a pointer to one. Note that this is a prefix use of ^.
Let us create a full record example :
type
TMyRecord = Record
name : String[20];
age : Integer;
end;
var
myRecord : TMyRecord;
myRecordPtr : ^TMyRecord;
begin
myRecord.name := 'Fred Bloggs';
myRecord.age := 23;
myRecordPtr := @myRecord;
ShowMessage(myRecordptr.name); // Displays 'Fred Bloggs'
end;
When we simply refer to the record field name, without a ^, Delphi is in fact adding one for us - it recognises what we are doing, and helps us make for more readable code.