Pointers and Pointer Types (Delphi)

From RAD Studio
Jump to: navigation, search

Go Up to Data Types, Variables, and Constants Index


A pointer is a variable that denotes a memory address. When a pointer holds the address of another variable, we say that it points to the location of that variable in memory or to the data stored there. In the case of an array or other structured type, a pointer holds the address of the first element in the structure. If that address is already taken, then the pointer holds the address to the first element.

Pointers are typed to indicate the kind of data stored at the addresses they hold. The general-purpose Pointer type can represent a pointer to any data, while more specialized pointer types reference only specific types of data. The PByte type is used for any byte data that is not character data.

On 32-bit platforms, a pointer occupies four bytes of memory as a 32-bit address. On 64-bit platforms, a pointer occupies eight bytes of memory as a 64-bit address.

This topic contains information on the following:

  • General overview of pointer types.
  • Declaring and using the pointer types supported by Delphi.


Overview of pointers

To see how pointers work, look at the following example:

 1         var
 2           X, Y: Integer;  // X and Y are Integer variables
 3           P: ^Integer;     // P points to an Integer
 4         begin
 5           X := 17;      // assign a value to X
 6           P := @X;      // assign the address of X to P
 7           Y := P^;      // dereference P; assign the result to Y
 8         end;

Line 2 declares X and Y as variables of type Integer. Line 3 declares P as a pointer to an Integer value; this means that P can point to the location of X or Y. Line 5 assigns a value to X, and line 6 assigns the address of X (denoted by @X) to P. Finally, line 7 retrieves the value at the location pointed to by P (denoted by ^P) and assigns it to Y. After this code executes, X and Y have the same value, namely 17.

The @ operator, which is used here to take the address of a variable, also operates on functions and procedures. For more information, see The @ Operator and Procedural Types in Statements and Expressions.

The caret symbol ^ has two purposes, both of which are illustrated in our example. When it appears before a type identifier:

^typeName

the caret symbol denotes a type that represents pointers to variables of type typeName.

When the caret symbol appears after a pointer variable:

pointer^

the caret dereferences the pointer; that is, it returns the value stored at the memory address held by the pointer.

This example might seem like a roundabout way of copying the value of one variable to another - something that we could have accomplished with a simple assignment statement. But pointers are useful for several reasons. First, understanding pointers will help you to understand the Delphi language, since pointers often operate behind the scenes in code where they don't appear explicitly. Any data type that requires large, dynamically allocated blocks of memory uses pointers. Long-string variables, for instance, are implicitly pointers, as are class instance variables. Moreover, some advanced programming techniques require the use of pointers.

Finally, pointers are sometimes the only way to circumvent Delphi's strict data typing. By referencing a variable with an all-purpose Pointer, casting the Pointer to a more specific type, and then dereferencing it, you can treat the data stored by any variable as if it belonged to any type. For example, the following code assigns data stored in a real variable to an integer variable:

type
  PInteger = ^Integer;
var
  R: Single;
  I: Integer;
  P: Pointer;
  PI: PInteger;
begin
  ...
  P := @R;
  PI := PInteger(P);
  I := PI^;
end;

Of course, reals and integers are stored in different formats. This assignment simply copies raw binary data from R to I, without converting it.

In addition to assigning the result of an @ operation, you can use several standard routines to give a value to a pointer. The New and GetMem procedures assign a memory address to an existing pointer, while the Addr and Ptr functions return a pointer to a specified address or variable.

Dereferenced pointers can be qualified and can function as qualifiers, as in the expression P1^.Data^.

The reserved word nil is a special constant that can be assigned to any pointer. When nil is assigned to a pointer, the pointer doesn't reference anything.

Using Extended Syntax with Pointers

The {$EXTENDED} compiler directive affects the use of the caret (^). When {$X+} is in effect (the default), you can omit the caret when referencing pointers. The caret is still required when declaring a pointer and for resolving the ambiguity when a pointer points to another pointer. For more information, see Extended syntax (Delphi).

With extended syntax enabled, you can omit the caret when referring to a pointer, as in the following example:

{$X+}
 type
   PMyRec = ^TMyRec;
   TMyRec = record
     Data: Integer;
   end;

 var
   MyRec: PMyRec;

 begin
   New(MyRec);
   MyRec.Data := 42;  {#1}
 end.

When extended syntax is not enabled, the line marked {#1} would typically be expressed as:

 MyRec^.Data := 42;

Pointer Types

You can declare a pointer to any type, using the syntax:

type pointerTypeName = ^type

When you define a record or other data type, it might be useful to also define a pointer to that type. This makes it easy to manipulate instances of the type without copying large blocks of memory.

Note: You can declare a pointer type before you declare the type it points to.

Standard pointer types exist for many purposes. The most versatile is Pointer, which can point to data of any kind. But a Pointer variable cannot be dereferenced; placing the ^ symbol after a Pointer variable causes a compilation error. To access the data referenced by a Pointer variable, first cast it to another pointer type and then dereference it.

Character Pointers

The fundamental types PAnsiChar and PWideChar represent pointers to AnsiChar and WideChar values, respectively. The generic PChar represents a pointer to a Char (that is, in its current implementation, to a WideChar). These character pointers are used to manipulate null-terminated strings. (See "Working with null-terminated strings" in String Types (Delphi).)

Note: Do not cast non-character pointer types to PChar to do pointer arithmetic. Instead, use the PByte pointer type, which is declared with the {$POINTERMATH ON} compiler directive.

Byte Pointer

The fundamental type PByte represents a pointer to any byte data that is not character data. This type is declared with the {$POINTERMATH ON} compiler directive:

function TCustomVirtualStringTree.InternalData(Node: PVirtualNode): Pointer;
begin
  if (Node = FRoot) or (Node = nil) then
    Result := nil
  else
    Result := PByte(Node) + FInternalDataOffset;
end;

Type-checked Pointers

The $T compiler directive controls the types of pointer values generated by the @ operator. This directive takes the form of:

{$T+} or {$T-}

In the {$T-} state, the result type of the @ operator is always an untyped pointer that is compatible with all other pointer types. When @ is applied to a variable reference in the {$T+} state, the type of the result is ^T, where T is compatible only with pointers to the type of the variable.

Other Standard Pointer Types

The System and SysUtils units declare many standard pointer types that are commonly used.

Use the {POINTERMATH <ON|OFF>} directive to turn pointer arithmetic on or off for all typed pointers, so that increment/decrement is by element size.

Selected pointer types declared in System and SysUtils

Pointer type Points to variables of type

PString

UnicodeString

PAnsiString

AnsiString

PByteArray

TByteArray (declared in SysUtils). Used to typecast dynamically allocated memory for array access.

PCurrency, PDouble, PExtended, PSingle

Currency, Double, Extended, Single

PInteger

Integer

POleVariant

OleVariant

PShortString

ShortString. Useful when porting legacy code that uses the old PString type.

PTextBuf

TTextBuf (declared in SysUtils). TTextBuf is the internal buffer type in a TTextRec file record.)

PVarRec

TVarRec (declared in System)

PVariant

Variant

PWideString

WideString

PWordArray

TWordArray (declared in SysUtils). Used to typecast dynamically allocated memory for arrays of 2-byte values.

See Also