Pointers & Dynamic Memory
With {$T+} (typed @ operator), @X has type ^Integer instead of untyped Pointer, which catches more mistakes.
18.1 Pointer basics
type "pointer to T" @X / Addr(X) the value P points to (dereference) pointer to nothing untyped pointer (like C void*)
P <> nil (also works for procedural and method variables) With {$T+} (typed @ operator), @X has type ^Integer instead of untyped Pointer, which catches more mistakes.
program PointerBasics;
{$mode objfpc}
var
X: Integer;
P: ^Integer;
begin
X := 10;
P := @X; // P points to X
P^ := 20; // changes X through P
Writeln(X); // 20
New(P); // allocate an Integer on the heap
P^ := 42;
Writeln(P^); // 42
Dispose(P); // free it
P := nil; // avoid a dangling pointer
end.18.2 Allocation routines
New(P) / Dispose(P) allocate/free one typed variable; initializes/finalizes managed fields (strings in records) GetMem(P, Size) / FreeMem(P) allocate/free a raw block of bytes (uninitialized) GetMem + zero fill ReallocMem(P, NewSize) resize a block FillChar(Buf, Count, Value) fill memory with a byte Move(Src, Dst, Count) copy memory (handles overlap) Initialize, Finalize manually initialize/finalize managed types in raw memory
Never use GetMem/FreeMem for records with managed fields unless you call Initialize/Finalize yourself.
type
PPerson = ^TPerson;
TPerson = record
Name: string; // managed field
Age: Integer;
end;
var
P: PPerson;
Buf: PByte;
begin
New(P); // Name initialized to ''
P^.Name := 'Grace';
P^.Age := 85;
Writeln(P^.Name); // P.Name also works: automatic dereference for records
Dispose(P); // frees Name's string data too
GetMem(Buf, 1024);
try
FillChar(Buf^, 1024, 0);
finally
FreeMem(Buf);
end;
end.18.3 Pointer arithmetic
Inc/Dec on typed pointers step by the size of the pointed-to type.
FPC allows P + N, P - Q, and P[N] on typed pointers; Delphi allows them for PByte/PChar and for other types under {$POINTERMATH ON}.
Pointer arithmetic bypasses all safety checks — keep it inside small, well-tested routines.
program PtrMath;
{$mode objfpc}
var
A: array[0..4] of Integer = (10, 20, 30, 40, 50);
P: PInteger;
I: Integer;
begin
P := @A[0];
Inc(P, 2); // advances by 2 * SizeOf(Integer) bytes
Writeln(P^); // 30
Dec(P);
Writeln(P^); // 20
P := @A[0];
for I := 0 to 4 do
Write(P[I], ' '); // indexing a typed pointer: FPC; Delphi needs {$POINTERMATH ON}
Writeln;
end.18.4 Common pointer bugs
using memory after Dispose/Free set to nil after freeing; FreeAndNil for objects forgetting to free
try/finally; ownership rules; heaptrc/FastMM reports set to nil; single owner dereferencing nil or garbage check Assigned; initialize pointers writing past an allocation use SizeOf, {$R+}, dynamic arrays instead of raw blocks