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