Pointer Basics
Pascal pointers are variables that hold a memory address directly. A pointer type is declared by placing ^ before the type name; heap memory is allocated with New and the value at the pointed-to address is read or written using the ^ dereference operator. When the memory is no longer needed it is released with Dispose. Correct use of pointers makes it possible to build dynamic data structures such as linked lists and trees.
Syntax
{ -----------------------------------------------
Declaring a pointer type
----------------------------------------------- }
type
TypeNamePtr = ^TypeName; { Defines a pointer type to an existing type }
var
ptrVar : ^TypeName; { Can also be declared directly without a named type }
{ -----------------------------------------------
Allocating and releasing heap memory
----------------------------------------------- }
New(ptrVar); { Allocates heap memory and stores the address in ptrVar }
Dispose(ptrVar); { Releases the heap memory. Access after release is forbidden. }
{ -----------------------------------------------
Dereferencing (^ operator)
----------------------------------------------- }
ptrVar^ := value; { Writes a value to the address the pointer points to }
variable := ptrVar^; { Reads the value from the address the pointer points to }
{ -----------------------------------------------
Address-of (@ operator)
----------------------------------------------- }
ptrVar := @existingVar; { Stores the address of an existing variable in ptrVar }
{ -----------------------------------------------
nil (null pointer)
----------------------------------------------- }
ptrVar := nil; { A safe initial value meaning "points to nothing" }
if ptrVar = nil then ... { Verify before access with a nil check }
Syntax Reference
| Syntax / Operator | Description |
|---|---|
^TypeName (in type declaration) | Declares a pointer type to the specified type. Often given a name in a TYPE declaration, e.g. type PIntPtr = ^Integer;. |
ptrVar^ (dereference) | Accesses the actual value at the address the pointer holds. Used for both reading and writing. |
@variable | Obtains the memory address of a variable. Used when you want to manipulate an existing variable through a pointer. |
New(p) | Allocates heap memory sized to the type of p^ and stores the address in p. |
Dispose(p) | Releases heap memory allocated with New. Passing nil causes a runtime error. |
nil | A pointer value meaning "points to nothing." Assigning it in place of an uninitialised pointer is safer. |
Assigned(p) | Returns True if p is not nil. Equivalent to p <> nil but easier to read. |
Sample Code
db_pointer.pas
{ db_pointer.pas — Sample demonstrating Pascal pointer basics }
{ Uses Dragon Ball character data to show }
{ pointer type declaration, New / Dispose, and dereferencing }
{
Compile and run:
fpc db_pointer.pas && ./db_pointer
}
program db_pointer;
{ -----------------------------------------------
Define a record type and its corresponding pointer type
----------------------------------------------- }
type
TFighter = record
name : string[20]; { Character name }
power_level: LongInt; { Power level }
end;
PFighter = ^TFighter; { Pointer type for TFighter }
var
{ -----------------------------------------------
Pointer variable declarations
----------------------------------------------- }
p1 : PFighter; { Pointer to heap-allocated fighter data }
p2 : PFighter; { Pointer to another fighter record }
p3 : PFighter; { Pointer to a stack variable (used with @) }
{ A regular record variable on the stack }
local_fighter : TFighter;
{ Variables for the integer pointer example }
pi : ^LongInt;
score : LongInt;
begin
WriteLn('===== Dragon Ball Pointer Sample =====');
WriteLn('');
{ -----------------------------------------------
1. Allocate heap memory with New and write values
----------------------------------------------- }
New(p1); { Allocates TFighter-sized heap memory }
p1^.name := 'Son Goku'; { Dereference and write to the field }
p1^.power_level := 9000;
New(p2);
p2^.name := 'Vegeta';
p2^.power_level := 8500;
WriteLn('--- Fighter data allocated with New ---');
WriteLn(' p1^ : ', p1^.name, ' Power level = ', p1^.power_level);
WriteLn(' p2^ : ', p2^.name, ' Power level = ', p2^.power_level);
WriteLn('');
{ -----------------------------------------------
2. Update a value through dereferencing
----------------------------------------------- }
p1^.power_level := 150000000; { Super Saiyan awakening; update power level }
WriteLn('--- After updating power level ---');
WriteLn(' p1^ : ', p1^.name, ' Power level = ', p1^.power_level);
WriteLn('');
{ -----------------------------------------------
3. Get the address of a stack variable with @
----------------------------------------------- }
local_fighter.name := 'Piccolo';
local_fighter.power_level := 3500;
p3 := @local_fighter; { Store local_fighter's address in p3 }
WriteLn('--- Pointing to a stack variable with @ ---');
WriteLn(' p3^ : ', p3^.name, ' Power level = ', p3^.power_level);
{ The value of local_fighter can be changed through p3 }
p3^.power_level := 8000;
WriteLn(' After update via p3: local_fighter.power_level = ', local_fighter.power_level);
WriteLn('');
{ -----------------------------------------------
4. Basic operations with an integer pointer
----------------------------------------------- }
New(pi);
pi^ := 999999; { Write a value to the address the pointer points to }
score := pi^; { Read the value from the pointer into a variable }
WriteLn('--- Integer pointer ---');
WriteLn(' pi^ = ', pi^, ' score = ', score);
Dispose(pi); { Release heap memory that is no longer needed }
WriteLn(' pi has been Disposed.');
WriteLn('');
{ -----------------------------------------------
5. nil check and the Assigned function
----------------------------------------------- }
p3 := nil; { p3 was pointing to a stack variable; reset it to nil }
WriteLn('--- nil / Assigned check ---');
if not Assigned(p1) then
WriteLn(' p1 is nil.')
else
WriteLn(' p1 points to a valid address. (Assigned = True)');
if p3 = nil then
WriteLn(' p3 is nil.');
WriteLn('');
{ -----------------------------------------------
6. Release heap memory
----------------------------------------------- }
Dispose(p1);
Dispose(p2);
WriteLn('--- p1 and p2 have been Disposed. ---');
WriteLn('==========================================');
end.
fpc db_pointer.pas && ./db_pointer Free Pascal Compiler version ... Linking ./db_pointer ===== Dragon Ball Pointer Sample ===== --- Fighter data allocated with New --- p1^ : Son Goku Power level = 9000 p2^ : Vegeta Power level = 8500 --- After updating power level --- p1^ : Son Goku Power level = 150000000 --- Pointing to a stack variable with @ --- p3^ : Piccolo Power level = 3500 After update via p3: local_fighter.power_level = 8000 --- Integer pointer --- pi^ = 999999 score = 999999 pi has been Disposed. --- nil / Assigned check --- p1 points to a valid address. (Assigned = True) p3 is nil. --- p1 and p2 have been Disposed. --- ==========================================
Common Mistakes
Dereferencing an uninitialised pointer
A pointer variable immediately after declaration does not hold nil; it holds an undefined value. Dereferencing (p^) before allocating memory with New or GetMem accesses an invalid address.
Not setting a pointer to nil after Dispose
A pointer that has been released with Dispose becomes a dangling pointer if accessed again. Assigning p := nil immediately after Dispose helps prevent accidental reuse through nil checks.
Confusion over the position of ^ compared with C
In Pascal, a pointer type in a type declaration is written as PMyType = ^MyType (^ before the type), while dereferencing is written as p^ (^ after the variable). Mixing this up with C's *p and writing p* causes a compile error.
Overview
Pascal pointers are type-safe: declaring them as ^TypeName lets the compiler detect unintended type mismatches at compile time. Heap memory is allocated with New and released with Dispose. Assigning nil to a pointer variable after release helps prevent double-free and dangling pointer bugs. Combined with record types, pointers make it possible to implement dynamic data structures such as linked lists and trees — that application is covered on a separate page. For records, which are often used as the pointed-to type, see Record Types (record). For another approach to dynamic arrays see Dynamic Arrays (GetMem / SetLength).
If you find any errors or copyright issues, please contact us.