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.
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.
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.
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:
- Static variables are declared within the program (using a variable name), whereas dynamic variables are external to the program (and accessible via pointers).
- The content of static variables is located in the "program memory", whereas the content of dynamic variables is located on the heap.
- Before using dynamic variables, you'll have to reserve memory for them (in the heap). This memory area is exclusively reserved for you and you should free the memory if you don't need it anymore. If you are interested in details, please have a look at the article Heap allocation strategy at the Free Pascal website.
- The heap allocates memory from the operating system on an as-needed basis. If the attempt to reserve OS memory fails, the default action is the generation of a runtime error 203; cf. the article The heap grows at the Free Pascal website.
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:
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.
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.