How to use pointer variables in Delphi?

What pointer variables are, how to describe and how to use them

Posted by: Alex A. Publish date: 28.03.2022

Pointer variables are a special type of variables that do not store values but just point to them – to the memory cell where these values are kept. And though there is a quite logical opinion that the usage of pointers can result in different errors in a program, pointer variables can be a very efficient tool for managing objects in the RAM of a computer.

A memory cell is a one-byte structure. As for objects that a program works with, they are usually significantly bigger. Consequently, a pointer keeps an address of only the first byte of the RAM sector where a particular object is stored. When you know the type and size of an object, you can read it entirely.

 

Description of the pointer variables

 

A pointer is specified with a keyword Pointer. As a rule, pointer variables are specified with the first letter of this name – P:

 

  var PIndexer: Pointer;//untyped pointer

 

The keyword Pointer is used for a so-called untyped pointer like in the case with an untyped file. An untyped pointer contains just an address of some memory cell. The object that is located starting with this cell can be of absolutely any type and size.

 

In Delphi, there are also typed pointers. They can point to an object of the relevant type and size. They can be named “point” as they still contain just an address of the first cell in the memory area where the object is located. And then its use in the program depends on the developer.

 

A typed pointer is specified with a keyword that defines a particular type and has a character ^:

 

  var PInteger: ^Integer;// pointer to a variable of the integer type

         PText: ^String;//pointer to a variable of the String type

 

It’s also possible to specify any type and assign a variable of this type:

 

type TMyType = Record

   X: Integer;

   S: String;

end;

 

var PMyPointer: ^TMyType;

 

It is possible to identify a type to use for describing pointer variables. It can be done for different reasons. For example, in procedures and functions, you can use only earlier described data types as parameters. For instance, the following description specifies the function with a parameter that is a pointer of the previously described type. The result of this function is also a pointer of this type:

 

type TMyPointer = ^TMyType;

 

function MyFunc(Point: TMyPointer): TMyPointer;

 

The use of pointer variables

   

The use of pointer variables presupposes:

  • Pointer value assignment
  • Pointer value change
  • Creation of a memory area of the necessary type and assignment of its address to the pointer
  • Recording of the value to the memory area addressed by the pointer and reading data
  • This memory area freeing

The described pointer without an assigned value points to an absolutely indefinite memory cell. Any efforts to use such a pointer may result in a program collapse. That’s why it is crucial to assign values to all pointers.

 

  1. A pointer can have the value of another pointer. As a result, both pointers will point to the same memory cell. You can also assign a null-value to a pointer using the keyword nil:

 

var P1, P2: Pointer;

begin

  P1:=P2;//Assignment of the value of another pointer

  P2:=nil;//Assignment of a null-value

end;

 

The pointer with a nil value doesn’t point to any memory cell and the only thing that you can do with it is to compare it with another pointer with the nil value.

 

  1. The value of the typed pointer can be increased or decreased by the size of the memory area that is occupied by the object of this type. For this aim, we should use the increment and decrement operations:

 

type P: ^Integer;

begin

  inc(P);// increase of pointers’ value by 4 bytes (size of Integer type) 

  dec(P);// decrease of pointers’ value by 4 bytes (size of Integer type) 

end;

 

A trial to execute the inc or dec operations with an untyped pointer will lead to an error at the compilation stage as the compiler doesn’t have any information on how the pointer’s value should be changed.

 

  1. With the procedure New, it is possible to create a memory area of the relevant type and assign its address to a pointer (to initiate a pointer):

 

var PInt: ^Integer;

begin

  New(PInt);// Pointer PInt gets the address of the created memory area of the type Integer

end;

 

As the memory area, which was created with the procedure New, is not linked to any variable but it contains a real value that is being used, you can consider that a value is linked to an unnamed variable. It is impossible to call it by name but it is possible to operate it using a pointer.

 

It is also possible to assign an object address to a pointer using an operation that is called “address taking” and is identified with the sign @. And here you do not need to create a memory area as it is already created with a preliminary description of this object:

 

var MyVar: TMyType;//Description of the variable, memory area of the relevant size is assigned

    P: ^TMyType;//A pointer of the relevant type is assigned

begin

  P:=@MyVar;//A pointer gets the address of the memory area that is occupied by the MyVar variable

end;

 

  1. If a memory area is already created and its address is assigned to a pointer, you can add the value of the object that corresponds to the pointer type into the memory cell addressed by this pointer. For this aim, there is an operation that is also identified with a character ^ that should be placed after the pointer’s name, for example, P^. This operation is called “pointer unnaming”. Moreover, with the help of this operation, you can do whatever is required with the value in this memory cell: 

 

var MyVar: Integer;

    P: ^Integer;

begin

  P:=@MyVar;//A pointer gets an address of the memory area that is occupied by MyVar

  P^:=2;//The value 2 is added to the memory cell located at the address of the variable MyVar

  Form1.Caption:=IntToStr(P^+3);//The number 5 will appear in the heading of the Form

end;

 

With common variables, everything is quite simple, but there is a question on how to get a value using a pointer’s address if a type of this variable is a record with several fields? Everything looks  quite similar:

 

type TMyRec = Record

    N: Integer;

    S: String;

end;

 

var MyRec: TMyRec;

    PRec: ^TMyRec;

 

begin

  PRec:=@MyRec;//MyRec A pointer gets an address of the memory area that is occupied by MyRec 

  PRec^.S:=’Data line’;//The pointer is used to introduce changes in the string field

  PRec^.N:=256;//The pointer is used to introduce changes in the number field

end;

 

Now you need to move an arrow from PRec: PRec.S:=’Data line’; and you will see that neither the compilator nor the program has shown any errors. It means that expressions PRec^.S and PRec.S are identical.

 

Now, let’s see how to get a value if a pointer is an element of the array, for example:

 

var PArray: Array[1..100] of ^Integer;

    X: Integer;

 

PArray^[10] and PArray[10]^ are not correct expressions. It is necessary to use brackets: 

 

X:=(PArray[10])^;

 

  1. The memory that is dedicated within the procedure New should be freed. To free the memory area addressed by the pointer that was initiated with the help of New, you can use the procedure Dispose :

 

var MyVar: TMyType;

    P: ^TMyType;

begin

  P:=@MyVar;

  Dispose(P);// Freeing of memory area addressed by pointer P

end;

 

During the Dispose procedure, the pointer again gets an indefinite value that even doesn’t equal nil and its usage can lead to indefinite results, including program collapse.

Talk to us and get your project moving
Book a free consultation with a solution expert.
Name
This field is required
E-mail
Company web site
This field is required
Phone Number
This field is required