Computing: Free Pascal Programming

Pointers - Part I: A general overview.

Part II: An introduction to linked lists Part III: An introduction to trees and graphs

Each variable, that you declare in a program, corresponds to some memory location defined by its address. The size of the memory area, reserved to keep a given variable, depends on the variable's data type. Examples: Variables of data type Byte use 1 byte of memory, Word variables use 2 bytes (as Integer variables normally do), variables of type Single use 4 bytes, Double variables use 8 bytes.

A typed pointer (there are also untyped pointers; cf. further down in the text) is a special kind of variable, that doesn't contain any data used by the program logic, but contains the address of another variable, in other words a typed pointer points to a variable of a given data type.

As typed pointers are data type dependent, the type of the pointer variable varies with the type of the variable it points to. A pointer pointing to an Integer variable has to be of type Integer pointer, a pointer pointing to a custom record of type TDate has to be of type TDate pointer. Once a pointer variable is defined to be of a certain type, it can point to data items of that type only!

The pointer type is defined by prefixing the base type (type of the data items that the pointer should point to) with the caret symbol (^). General format:
    type
        Ptr-type-identifier = ^Base-variable-type;

A pointer variable is declared as is a variable of any other data type, i.e. by indicating the pointer type. General format:
    var
        Ptr1, Ptr2: Ptr-type-identifier;

Examples
    type
        TPDate = ^TDate;
        TDate = record
           Day: 1..31;
           Month: 1..12;
           Year: 1900..3000;
        end;
    var
        PI1, PI2: ^Integer;
        PC: ^Char;
        Date: TDate;
        PDate: TPDate;
Note that in this example the variable Date is a record (of type TDate), the variable PDate a pointer to a record (of type TDate).

In the same way that the value of a "normal" variable isn't defined until it is initialized, the pointer variables declared above are undefined. All that we know about them is that they should point to a variable of a given data type. The address they should point to is undefined and there isn't any relationship between the pointers and a variable (in our example, TPDate and TDate are "related", but there isn't any relationship between PDate and Date).

Consider the following declarations:
    var
        iptr: ^Integer;
        n: Integer;
and lets try to represent this graphically.

Both the integer and the pointer are static variables, located somewhere in memory, suppose at addresses 0xBA75 and 0xBA81 respectively. The content of n (a data value) is actually undefined, as is the content of iptr (an address), what means that the location where iptr points to is undefined, too.

Free Pascal pointers: Declared but not yet initialized variables

To reset a numeric variable, we assign it the value 0, to reset a string variable we assign it to '' (an empty string). Similarly, we can reset a pointer, by setting it to nil.
    iptr := nil

This actually sets the address pointed to by iptr to 0x0. If you try to read the value at this address, you'll get an Access violation as shown on the screenshot below.

Free Pascal pointers: Error message when trying to read the value pointed to by a nil pointer

Note: We have seen that pointers store a memory address. These are actually values with a word size. However, we cannot assign a pointer a word value; in fact, the only value we can directly assign to a pointer is nil. Also, it is not possible to print a variable of some pointer data type. As for the assignment, we'll get a compilation error. If we try the assignment
    iptr := 1000;
we get the error message Incompatible types: got "SmallInt" expected "^LongInt".
And if we try the statement
    Writeln(iptr);
we get the error message Can't read or write variables of this type.

Pointers referencing static variables.

Static variables are variables declared in the program and located in "program memory". They start to exist at the moment when they are declared and end to exist either when the program terminates, or, in the case of variables local to a procedure or function when control is given back to the calling program block. To assign the address of a variable to a pointer, we use the address operator (@). Example:
    n := 24;
    iptr := @n;

This assigns the value 24 to the Integer variable n and the address of the variable n to the pointer iptr. The pointer iptr now points to a memory location that contains the integer value 24, as shown on the figure below.

Free Pascal pointers: Pointer referencing a static variable in 'program memory'

Once a pointer has been assigned the address of a variable, we can use the pointer to access this variable's content. This is done by dereferencing the pointer using the caret (^) symbol. Example:
    program pointers01;
    var
        N: Integer;
        IPtr: ^Integer;
    begin
        N := 24;
        IPtr := @N;
        Writeln(N, ' ', IPtr^);
        Writeln; Write('ENTER to terminate '); Readln;
    end.
The output of this program will be:
    24  24

Note: Attempting to dereference a pointer that currently possesses the value nil constitutes a fatal error.

Consider the following code:
    program pointers02;
    var
        N1, N2: Integer;
        IPtr, IPtr1, IPtr2: ^Integer;
    begin
        N1 := 100; N2 := 200;
        IPtr1 := @N1; IPtr2 := @N2;
        Writeln(IPtr1^, ' ', IPtr2^);
        IPtr := IPtr1;
        IPtr^ += IPtr2^;
        Writeln(IPtr1^, ' ', IPtr2^, ' ', IPtr^);
        IPtr^ := 500;
        Writeln(IPtr1^, ' ', IPtr2^, ' ', IPtr^);
        IPtr := IPtr2;
        Writeln(IPtr1^, ' ', IPtr2^, ' ', IPtr^);
        Writeln(N1, ' ', N2);
        Writeln; Write('ENTER to terminate '); Readln;
    end.
The output of this program will be:
    100  200
    300  200  300
    500  200  500
    500  200  200
    500  200

At the beginning IPtr1 points to N1 (value 100) and IPtr2 points to N2 (value 200), thus printing IPtr1^ and IPtr2^ will give "100  200". We then assign the pointer IPtr1 to the pointer IPtr; IPtr thus points to N1 (value 100). Now, we add the value pointed to by IPtr2 (200) to the value pointed to by IPtr (100); IPtr will thus point to the value 100 + 200 = 300. As IPtr points to N1, this means that N1 is now 300, and printing IPtr1^ (IPtr pointing to N1) will also give 300. Setting the variable pointed to by IPtr (N1) to 500 and printing IPtr1^ (IPtr also pointing to N1) will also give 500. Finally, reassigning IPtr2 to IPtr, IPtr now points to N2, that has not been changed since the beginning, and both IPtr and IPtr2 point to the value 200. Printing out the variables N1 and N2 shows well that it's the values of these variables that have been modified by working with our dereferenced pointers.

Pointers referencing dynamic variables.

The variables declared within a program are called static variables, because the memory location where their content is located is fixed relative to the begin of the program code (speaking assembly: what I called "program memory" above corresponds to the .data or .bss section). The Pascal programming language allows another kind of variables: dynamic variables. There are a number of fundamental differences between dynamic and static variables:

Note: A memory area, that for one reason or another, becomes inaccessible is automatically freed. Also, the lifetime of dynamic variables end if there isn't anymore a pointer pointing to it. Thus, in a "normal situation" where the lifetime of all pointer variables ends with the termination of the program, the lifetime of the dynamic variables also ends and it's not mandatory to dispose the corresponding heap memory.

To dynamically create and allocate space for a variable on the heap, we use the function New(). Example: Reserve space for one variable of data type Integer and point to that location using the Integer pointer IPtr:
    New(IPtr);

IPtr contains now the starting address of the memory area newly allocated on the heap and we can place an Integer value at that memory location using the dereferenced pointer:
    IPtr^ := 24;

And finally, lets free the allocated memory (using the function Dispose):
    Dispose(IPtr);
To note that when a pointer is disposed of, it won’t be possible to use it again.

As before, we can represent this graphically:

Free Pascal pointers: Pointer referencing a dynamic variable on the heap

Here is a new version of our pointers02 program from above (using dynamic variables this time).
    program pointers03;
    var
        IPtr, IPtr1, IPtr2: ^Integer;
    begin
        New(IPtr); New(IPtr1); New(IPtr2);
        IPtr1^ := 100; IPtr2^ := 200;
        Writeln(IPtr1^, ' ', IPtr2^);
        IPtr := IPtr1;
        IPtr^ += IPtr2^;
        Writeln(IPtr1^, ' ', IPtr2^, ' ', IPtr^);
        IPtr^ := 500;
        Writeln(IPtr1^, ' ', IPtr2^, ' ', IPtr^);
        IPtr := IPtr2;
        Writeln(IPtr1^, ' ', IPtr2^, ' ', IPtr^);
        Writeln; Write('ENTER to terminate '); Readln;
    end.
The output of the program will be the same as above (the explanations are quite the same, too):
    100  200
    300  200  300
    500  200  500
    500  200  200

Pointer arithmetic.

An array of pointers may be used to point to an array of whatever data type, each element of the pointer record pointing to the corresponding value of the data record. Here is an example with an array of Double numbers:
    program pointers04;
    var
        I: Integer;
        D: array[1..5] of Double = (1.1, 2.2, 3.3, 4.4, 5.5);
        DPtr: array[1..5] of ^Double;
    begin
        // Fill the pointer array with the addresses of the array elements
        for I := 1 to 5 do
            DPtr[I] := @D[I];
        // Print out of the values using the pointer array
        for I := 1 to 5 do
            Writeln(' Value of D[', I, '] = ' , DPtr[I]^ );
        Writeln; Write('ENTER to terminate '); Readln;
    end.
And the program output:
    Value of D[1] = 1.1000000000000001E+000
    Value of D[2] = 2.2000000000000002E+000
    Value of D[3] = 3.2999999999999998E+000
    Value of D[4] = 4.4000000000000004E+000
    Value of D[5] = 5.5000000000000000E+000

We will now simplify the code of this sample: Instead of defining a pointer for each array element, we will use a single pointer and, by incrementing/decrementing this pointer, access the different elements of the data array. Incrementing/decrementing a pointer, is that permitted? In classic Pascal, operations on pointers are very limited. You can compare two pointers to check if they are equal or unequal (or checking if a pointer is nul; checking if a pointer is greater or less than another pointer yields a compilation error), but arithmetic operations are not supported. Modern versions of Pascal, including Free Pascal, support pointer manipulation as in C. This is what some people call C pointer nonsense. I'm not qualified to comment this term, and even if pointer arithmetic is somewhat weird, it can be really useful. So: Free Pascal allows to increment and to decrement pointers. What do such operations mean? No, it's not the same than operations on numerical variables! Incrementing a pointer (by 1) means letting it point to the "next address" by adding the size of the data type, that it points to, to the actual address value. Thus, in the case of a Char pointer, the address is incremented by 1, in the case of a Double pointer, it is incremented by 8. Similarly decrementing a pointer makes it point to the "previous address". And using the instructions Inc(Ptr, N) and Dec(Ptr, N), with N being a (positive) Integer, make the pointer point to a memory area that is located at an address that is (N * pointer type size) more resp. less than the actual address. It is evident that this can mess up a program; using pointer arithmetic with an array, however, is reasonable, and the best thing is that the particularities of pointer arithmetic is entirely transparent.

Here is the new version of the sample pointers04. As said before, we use here a single pointer, that we let point to the first element of the array at the begin of the program and then, when iterating the array to print it out, increment the pointer and by this make it point to the next element. The output of the program is the same as for sample pointers04.
    program pointers05;
    var
        I: Integer;
        D: array[1..5] of Double = (1.1, 2.2, 3.3, 4.4, 5.5);
        DPtr: ^Double;
    begin
        // Point to the first element of the array
        DPtr := @D[1];
        // Print out of the values using the pointer incremented at each iteration
        for I := 1 to 5 do begin
            Writeln(' Value of D[', I, '] = ' , DPtr^);
            Inc(DPtr);
        end;
        Writeln; Write('ENTER to terminate '); Readln;
    end.

Here is another example, where the iteration is done from the last to the first array element, and only every second element is printed.
    program pointers06;
    var
        I: Integer;
        D: array[1..5] of Double = (1.1, 2.2, 3.3, 4.4, 5.5);
        DPtr: ^Double;
    begin
        // Point to the last element of the array
        DPtr := @D[5];
        // Print out of the values using the pointer decremented at each iteration by 2
        I := 5;
        while I >= 1 do begin
            Writeln(' Value of D[', I, '] = ' , DPtr^ );
            I -= 2;
            Dec(DPtr, 2);
        end;
        Writeln; Write('ENTER to terminate '); Readln;
    end.
Program output:
    Value of D[5] = 5.5000000000000000E+000
    Value of D[3] = 3.2999999999999998E+000
    Value of D[1] = 1.1000000000000001E+000

Pointers to records, arrays, strings, pointers.

Independently if such code is really useful, the following samples show some possibilities that Free Pascal pointers have to offer and, if perhaps you asked yourself how to use these rather weird constructs, show you the answer to your question.

A pointer to a record is of data type "record pointer", thus, the dereferenced pointer may be used to access the individual record items. Example:
    program pointers07;
    type
        TEmployee = record
            Name, FirstName: string;
            Salary: Single;
        end;
    var
        RPtr: ^TEmployee;
    begin
        New (RPtr);
        RPtr^.Name := 'Flintstone';
        RPtr^.FirstName := 'Fred';
        RPtr^.Salary := 2400;
        Writeln('The salary of ', RPtr^.FirstName, ' ', RPtr^.Name, ' is ', RPtr^.Salary:0:2, '$');
        Dispose (RPtr);
        Writeln; Write('ENTER to terminate '); Readln;
    end.
Program output:
    The salary of Fred Flintstone is 2400.00$

A pointer to an array is of data type "array pointer", thus (as in C), the dereferenced pointer may be used to access the individual elements of the array. Example:
    program pointers08;
    type
        TArray = Array[0..9] of Integer;
    var
        I: Integer;
        APtr: ^TArray;
    begin
        New (APtr);
        for I := 0 to 9 do
            APtr^[I] := 200 * I;
        for I := 0 to 9 do
            Write (APtr^[I] div 2, ' ');
        Dispose (APtr);
        Writeln; Write('ENTER to terminate '); Readln;
    end.
Program output:
    0 100 200 300 400 500 600 700 800 900

A pointer to a string is of data type "string pointer", thus, the dereferenced pointer may be used to access the individual characters of the string. As the length of Pascal strings is always defined, it is possible to use the Length function with a string pointer. Example:
    program pointers09;
    var
        SPtr: ^string;
    begin
        New (SPtr);
        SPtr^ := 'abcdefghijklmnopqrstuvwxyz';
        Writeln('First letter of string = ', SPtr^[1]);
        Writeln('10th  letter of string = ', SPtr^[10]);
        Writeln('Last  letter of string = ', SPtr^[Length(SPtr^)]);
        Dispose (SPtr);
        Writeln; Write('ENTER to terminate '); Readln;
    end.
Program output:
    First letter of string = a
    10th letter of string = j
    Last letter of string = z

A pointer to a pointer is a chain of pointers, implementing a multiple indirection. Normally, a pointer contains the address of a variable. When we define a pointer to a pointer, this pointer contains the address of a second pointer, which points to the location that contains the actual value of the variable, as shown on the figure below.

Free Pascal pointers: Pointer to a pointer = form of multiple indirection

A pointer to a pointer is a pointer variable of data type pointer and must be declared a such. Example for a Double variable:
    type
        TDPtr  = ^Double;
        TPDPtr = ^TDPtr;

Here is an example:
    program pointers10;
    type
        TIptr  = ^Integer;
        TPIptr = ^TIptr;
    var
        N: Integer;
        IPtr: TIptr;
        PIptr: TPIptr;
    begin
        N := 200;
        IPtr   := @N;
        PIPtr := @IPtr;
        IPtr^ := IPtr^ div 2;
        Writeln('N = ', N, ', IPtr^ = ', IPtr^, ', PIPtr^^ = ', PIPtr^^);
        Writeln; Write('ENTER to terminate '); Readln;
    end.
Program output:
    N = 100, IPtr^ = 100, PIPtr^^ = 100

First, we assign the value 200 to the variable N, then we assign the address of N to IPtr, and the address of IPtr to PIPtr. IPtr thus points to the address containing the value 200, whereas PIPtr points to the address that points to the address containing the value 200. The dereference of IPtr (IPtr^) corresponds to the content of the address where IPtr points to, i.e. the variable N. So, the instruction IPtr^ := IPtr^ div 2; will set N to 100. We than print out N (100), IPtr^ (corresponding to N = 100), and this "bizarre construct" PIPtr^^, that is displayed as being equal to 100, too. Lets have a look at this variable from left to right. PIPtr is a pointer pointing to IPtr (which is itself a pointer), thus PIPtr^ is a pointer, actually a pointer pointing to the variable N. Thus, dereferencing this pointer, we get the value of N (PIPtr^^, just as IPtr^ corresponds to N = 100).

The PChar data type.

The data type PChar is defined as a pointer to a single Char. PAnsiChar is an alias for PChar:
    type
        PChar = ^Char;
        PAnsiChar = PChar;

But, PChar allows additional operations. It can be interpreted as the Pascal equivalent of a C-style null-terminated string, i. e. a variable of type PChar can be seen as a pointer that points to an Array of Char, which is terminated by a null-character (#0).

The string itself is stored somewhere on the heap. It is obvious that this way of storing data is rather unsafe. Whereas the Pascal data type string always has a defined length, a PChar string only has a length if the string is terminated by #0. I suppose that you can imagine, what happens if you forget the #0... However, many libraries written in other programming languages make use of this dangerous data type and in order to facilitate interaction with them, Free Pascal provides this special support.

A PChar variable can have directly assigned a string literal. And, Write(ln) supports PChar arguments. If pMessage is a variable of type PChar, you can use it as follows:
    pMessage := 'Hello World!';
    Writeln(pMessage);

Note: Declaring a PChar variable and assigning it a literal is in fact pointing to the address of an "invisible constant value". Thus, it has the same effect as the declaration
    const P: PChar = 'Hello World!';
As a consequence, you are not allowed to alter any component of this value. Something like pMessage[11] := '?'; will crash the program!

The operations available for the data type string may not be used with PChar variables. Thus, for example, concatenating two PChar variables using the "+" operator is not possible. Free Pascal provides the unit "Strings" to manipulate PChar variables.

As PChar is in fact a pointer to a variable of data type Char, it is possible to indirectly assign a variable of type "string" to a "PChar" variable. To do this, we assign the PChar variable the address of the first character of the string. And, do not forget that our PChar string must be terminated with a null-character! Example:
    program pointers11;
    var
        sName, sMessage: string;
        pMessage: PChar;
    begin
        repeat
            Write('Please, enter your name? '); Readln(sName);
            if sName = '' then
                sMessage := 'Hello World!' + #0
            else
                sMessage := 'Hello ' + sName + '!' + #0;
            pMessage := @sMessage[1];
            Writeln(pMessage);
        until sName = '';
        Writeln; Write('ENTER to terminate '); Readln;
    end.
Program output (example):
    Please, enter your name? Aly
    Hello Aly!
    Please, enter your name? Jenny Jenkins
    Hello Jenny Jenkins!
    Please, enter your name?
    Hello World!

The following program shows, how to manipulate PChar variables using the functions and procedures of the Strings unit. The important thing here is that if we use a new PChar variable, we'll have to reserve space for the string first. This is done using the function StrAlloc, as shown in the sample program. For details concerning the PChar functions and procedures, have a look at the Reference guide for standard Free Pascal units.
    program pointers12;
    uses
        Strings;
    var
        sName: string;
        pName, pMessage: PChar;
    begin
        Write('Please, enter your name? '); Readln(sName);
        if sName <> '' then begin
            sName += #0;
            pName := @sName[1];
            pMessage := StrAlloc(StrLen(pName) + 7 + 1);
            pMessage := StrMove(pMessage, 'Hello ', 6 + 1);
            StrCat(pMessage, pName);
            StrCat(pMessage, '!');
            WriteLn(pMessage);
            Writeln; Write('ENTER to terminate '); Readln;
            end;
    end.
Program output (example):
    Please, enter your name? Aly
    Hello Aly!

The size of the memory to reserve on the heap actually equals the length of the name + 6 bytes for the string 'Hello ' + 1 byte for the exclamation mark + 1 byte for the null-character. If you want to release this memory before program termination, you can use the function StrDispose.

Pointers in functions and procedures.

Pointers may be passed as arguments to a function or procedure, and a function may return a pointer. If passing a pointer to a subroutine, you should do it by value. This makes sure that you don't change the pointer value within the subroutine. As this would be changing an address in memory, the results could be unpredictable.

Example of passing a pointer to a procedure: The following program prints out the elements of an array using a procedure. The array is passed to the procedure as a pointer.
    program pointers13;
    type
        TIPtr = ^Integer;
    var
        I: Integer;
        Numbers: array[1..10] of Integer;
        IPtr: TIptr;
    // Print procedure
    procedure PrintNumbers(PI: TIPtr);
    begin
        for I := 1 to 10 do begin
            Write(PI^, ' ');
            Inc(PI);
        end;
    end;
    // Main program
    begin
        for I := 1 to 10 do
            Numbers[I] := 2 * I;
        IPtr := @Numbers[1];
        PrintNumbers(IPtr);
        Writeln; Write('ENTER to terminate'); Readln;
    end.
Program output:
    2 4 6 8 10 12 14 16 18 20

Example of returning a pointer as function result: The following program prints out a series of random numbers between 0 and 99. The random numbers are generated by a function that returns a pointer to an array (containing the random numbers).
    program pointers14;
    type
        TIPtr = ^Integer;
    var
        I, J: Integer;
        IPtr: TIptr;
    // Random numbers function
    function RandomNumbers(N: Integer): TIPtr;
    var
        I: Integer;
        Numbers: array of Integer;
    begin
        SetLength(Numbers, N);
        for I := 0 to N - 1 do
            Numbers[I] := Random(100);
        RandomNumbers := @Numbers[0];
    end;
    // Main program
    begin
        Randomize;
        for J := 1 to 3 do begin
            IPtr := RandomNumbers(J * 10);
            for I := 1 to J * 10 do begin
                Write(IPtr^:2, ' ');
                Inc(IPtr);
            end;
            Writeln;
        end;
        Writeln; Write('ENTER to terminate'); Readln;
    end.
Program output (example):
    51   0   5 56 85 34 88 52 97 25
    88 68 61 61 80 66 48 62 55 34 53 14 87 84 37   4 49 98 54 51
    84 93 31 97 81 66 56 99 67 61 38 56 93 15 85 15 71 67 66 81 36   9 69 95   0 26   2 50 82 17

Dynamic memory allocation.

The New procedure in Pascal does not allow to choose how much memory to allocate at run time; thus when creating an array you must choose an upper bound in advance. If you are working with dynamic arrays, for example, you don't know in advance how much space the program will need on the heap. One possibility would be to preview a maximum number of elements and using this maximum as upper bound, even if the actual array has lots less elements. Another possibility would be to replace the array by a linked list. A third possibility is to use dynamic memory allocation, i.e. you reserve the memory that you need at runtime. In Free Pascal, this is done using the procedure GetMem, that allows to reserve a specified number of bytes on the heap. To free the memory allocated this way, use the procedure FreeMem.

The procedure ReallocMem changes the storage size of an existing block of storage. The size may be smaller or bigger. If smaller, then the existing storage is effectively truncated, the remainder being released. If larger, the storage is extended. Or a new block is allocated if necessary. In either case, the existing storage block data is preserved, and the new part is uninitialized.

The following program creates a dynamic array of random numbers on the heap. The maximum of numbers is arbitrarily fixed to 25,000. The space needed on the heap is dynamically allocated during runtime, thus only the space to store the actual number of random numbers will be used.
    program pointers15;
    type
        TArrayPtr = ^TArray;
        TArray = Array[0..25000] of LongInt;
    var
        M, N, R, I: Integer;
        Start, Alloc: Boolean;
        APtr: TArrayPtr;
    begin
        Randomize;
        Start := True; Alloc := False;
        repeat
            Write('Random numbers from 0 to 99 - how many do you want? '); Readln(M);
            if M > 0 then begin
                N := M;
                if Start then begin
                    GetMem(APtr, N * SizeOf(LongInt));
                    Start := False;
                end
                else begin
                    ReallocMem(APtr, N * SizeOf(LongInt));
                end;
                Alloc := True;
                for I := 0 to N - 1 do
                    APtr^[I] := Random(100);
                if N > 20 then begin
                    Writeln('The 20 first random numbers are: ');
                    R := 20;
                end
                else begin
                    Writeln('The random numbers are: ');
                    R := N;
                end;
                for I := 0 to R - 1 do
                    Write (APtr^[I], ' ');
                Writeln;
            end;
        until M <= 0;
        if Alloc then
            FreeMem(APtr, N * SizeOf(LongInt));
        Writeln; Write('ENTER to terminate '); Readln;
    end.
Program output (example):
    Random numbers from 0 to 99 - how many do you want? 20
    The random numbers are:
    33 36 23 40 15 25 26 46 1 92 75 12 4 19 25 86 85 67 87 23
    Random numbers from 0 to 99 - how many do you want? 20000
    The 20 first random numbers are:
    55 18 60 45 95 66 61 80 49 67 30 17 22 81 40 46 0 69 8 89
    Random numbers from 0 to 99 - how many do you want? 0

I used the LongInt data type, because the return value of the Random function is of that type. Note the usage of the function-call SizeOf(LongInt) to calculate the size of the memory area on the heap actually needed (size of one LongInt multiplied by actual number of array elements). The Boolean "Start" is used to check if it is the first time the repeat loop is executed; if yes, we make a new memory reservation, otherwise we reallocate a memory area. The Boolean "Alloc" is set when there has been a memory allocation; this permits to release the memory only if there is something to be released. Finally, make sure that the size of the memory bloc specified in FreeMem equals the size used when (re)allocating the memory (in our program N being the last non less or zero value entered as number of array elements).

The Pointer data type.

All pointers, that we have seen so far, including those created by dynamically allocating a sized area on the heap, point to variables of a given data type. The Pointer type provides a general use pointer to any memory based variable. That is, one that is accessed by reference (ex: Object, AnsiString, array). It is declared as follows:
    var
        generalPtr : Pointer;

Untyped pointers are dangerous - it is normally always better to use a specific pointer reference to the data type that you are using. Only then can you act up on the pointer. For a simple example, cf. The Pointer type in the SmartPascal section of the github website.

This terminates my introduction to Free Pascal pointers. Use the following link to download the tutorial samples source code.


If you find this text helpful, please, support me and this website by signing my guestbook.