Pascal Programming/Pointers

The new data type presented in this chapter adds another layer of abstraction to your repertoire: Pointers are by far the most complicated data type. If you master them, you have got what it takes to tackle even the supreme discipline of assembly programming. So, let’s get started!

Indirection
In Pascal there are two kinds of variable types. While using static variables, the compiler already knows which memory chunk will be used in advance. Dynamic variables, however, are, hence their name, dynamic in that they will be occupying different, unpredictable memory segments.
 * So far we have been using static variables. They exist during the entire execution of a block, e.&#8239;g. while a  is running or just during execution of a routine.
 * There is another kind called dynamic variables. They do not necessarily “exist” during the entire block. That means, there is no static memory allocated, but the used memory space varies each time the program runs.

Memory is referred to by addresses. An address is, in CS, simply a number, an  value so to speak. When you want to refer to a certain memory block, you use its address.

The pointer data type is a value that stores an address. This address can then be used to access the memory it is referring to. A pointer, however, is just that: It is pointing, but not making any statement as regards to “whom”, what variable this block of memory “belongs.”

Declaration
In Pascal, a pointer data type declaration starts with a  (up arrow), or alternatively and more frequently the   (caret) character, followed by the name of a data type. A variable of this pointer data type can point to a single  value (and no other data type). In Pascal all pointer data types have to indicate the data type of the value the pointer is referring to. This is because a pointer alone is just an address: An address merely points to the start of a memory block. There is no statement with respect to this block’s size, its length. The domain restriction, the specification of targeted value’s data type, tells the compiler “how large” a memory block will be, and in consequence how to properly read and write, how to access it.

Unlike any other data type, a pointer data type is the only data type that can use data types not declared yet. Below you will see a usage scenario, but let’s continue in the script.

Allocating memory
When you are declaring a variable in the ‑section, you are declaring a static variable. In the following code fragment  is a static variable, thus its memory location is already known. At this point, there is no memory space alloted to a  value yet. There is already space to store a pointer value, the address of a  value, but we do not have any space available to put it, a   value, anywhere.

In Pascal you will first need to invoke the  to get memory assigned to your. takes one pointer variable as an argument and will reserve enough memory space to hold one value of the pointer’s domain. After this operation As with all variables of any kind, the memory space we have acquired now is totally undefined (unintialized).
 * you occupy additional memory for, in this case, one  value the   previously did not “own”, and
 * , the pointer variable itself, will give us the address of this newly allocated memory.

Dereferencing
To use the memory we just gained we will have to follow a pointer. This is done by appending  (or usually  ) to the name of the pointer variable. This action is called dereferencing. The pointer is a (kind of) reference to the underlying  value. This  value does not have a name, but you use the pointer to access it anyway.

On this dereferenced variable we can perform all operations permissible on the pointer’s domain data type. I.&#8239;e. here we are allowed to assign a  value   to it, and then use it, for instance, in a   as demonstrated above.

Note that something like will not work, because in this case   simply refers to the pointer, the address storage. In Pascal it is forbidden to directly assign addresses to pointers, other than by using. For the special case of, see below.
 * The expression  has the data type.
 * The expression  has the data type.

Releasing memory
After invoking  the respective memory is exclusively reserved to your. This memory management occurs outside of your. It is a typical task of the respective OS.

To reverse the operation of, there is a dedicated   “unreserving” memory:. takes the name of a pointer variable, and releases previously with  allocated memory. After a  you may not follow, dereference, the pointer anymore. Nevertheless the pointer itself still stores the address where, in this case, the referenced  value was. Meanwhile, the “freed” memory may be used again for something or by someone else.

Lifetime
In Pascal, memory of dynamic variables remains reserved
 * as long as it is accessible, that means at least one pointer must point to it, or
 * until you specifically request to “unreserve” memory.

If a chunk of memory is rendered inaccessible by some operation, it is automatically released. This can happen implicitly: In the  above the pointer variable   is “gone” upon   termination. Because this variable is/was the only pointer (left) pointing to our previously reserved  value, there is an automatic “invisible”. Insofar, the explicit  from our side was not necessary.

However, unfortunately not all compilers comply with this specification as laid out in the Pascal ISO standards. For instance, Delphi, as well as the FPC (even in its compatibility mode, as of version 3.2.0) will not issue an automatic. There, an explicit  is necessary. Rest assured, using the GPC it is not necessary though; the GPC fully complies with the ISO standard 7185 level 1.

Note, that memory accessibility is transitive: This means that, for instance, a pointer pointing to a pointer pointing to the memory still satisfies the accessibility requirement.

Indication
The additional housekeeping of allocating and releasing memory may seem like quite a hassle, so when does that make sense? Furthermore, pointer values are frequently used to implement variable parameters of routines: Due to its smaller size passing a single pointer value can be faster than passing, that means copying, for instance an entire. This kind of use of pointers is completely transparent. Pascal equips you with an adequate language construct; you will learn more about variable parameters in the chapter on scopes.
 * All variables declared in a -section need to indicate their size in advance. For some applications, however, you do not know how much data you will need to store and process. Pointers are a means to overcome this limitation. Further below we will explore how.
 * Pointer values can be used to represent graphs, networks, of data, allowing you to put everything into relation with each other. This means you do not need to store the same datum multiple times. A pointer value is usually, with respect to its memory requirements, a comparatively small data type. Handling pointers trades lower memory space demand for increased complexity.

Nil pointers
All pointers can be assigned a literal value. The  pointer value represents the notion “not pointing anywhere in particular.”

Coincidentally,  is the only pointer value that could be used for a pointer literal. There is no other pointer value that you could possibly specify anywhere in your source code. This also means you cannot explicitely compare any specific pointer value except.

Note that  is fundamentally different to an unintialized variable. You are allowed to read the value of a pointer that has been assigned the value, but you are still forbidden to attempt reading the value of a variable that has not been assigned any value at all.

Permissible operators
In the introduction we used the analogy comparing pointers to  values. However, this is really just that. Unlike  values, pointers are by no means “ordered”; they do not belong the class of ordinal data types. There is no,  ,   defined for a pointer, but also ordering comparison operators like   or   do not apply to pointers, not to mention any arithmetic operator is invalid in combination with a pointer value.

The only operators applicable to pointers are It may seem at first like quite a restriction, but it prevents you from doing potentially harmful, or even just stupid stuff.
 * , do two pointer values refer to the same address,
 * , do two pointer values refer to different addresses, and
 * , the assignment of a pointer value, either  or the value of an already defined pointer variable of the same data type, to a pointer variable.

Chicken or egg
Pointers are the only data type that can be declared using a data type yet to be declared. This circumstance makes it possible to declare data types containing pointers, possibly to the data type being declared at hand or other yet to be declared data types. This is possible because a pointer to  has the same memory requirements as a pointer to   or any other data type. The domain restriction of a pointer is not (necessarily/explicitly) stored in the.

In the following code fragment  is not yet declared, but you are still allowed declare a new pointer data type with it anyway: Yet you cannot reverse the order of the declarations of  and  ; the compiler cannot magically conclude  is a pointer until it has actually seen/read the respective declaration.

Putting things together
Now we can use this data structure to dynamically store a series of numbers. Pay attention when to derefercene the pointer in the following code: The entire  contains one static variable. Only the variable  was declared by you. During run-time, however, while the  is running you will have at one point two additional   values at your disposal.

Take notice of this example’s order of  statements: The supplied pointer variable must be valid, so a reverse order would not be possible in this specific case here.

Concededly, this example could have been better implemented by simply declaring two  variables. The true power of pointers becomes apparent when you are, unlike the above code, use pointers as a means of abstraction. This chapter’s exercises will delve into that.

Routines
In particular, let’s first explore a special kind of pointers: Routine parameters, that is functional and procedural parameters, are parameters of routines that allow you to statically modify the routine’s behavior by virtually passing the address of another routine. Let’s see how this works.

Declaration and use
In the formal parameter list of a routine you can declare a parameter that looks just like a routine signature: Inside the definition of  you can use the parameter   as if it was a regular   declared and defined before and outside of. However, at this point it is not known what function will be used. The actual parameter  is in fact a pointer. We only know that this pointer’s “domain” is a, any  without parameters and returning an   value, but this is already enough we need to know.

One routine fits it all
To call this kind of routine you will need to specify an appropriate routine designator that matches the signature as regards to order, number and data types of parameters and, if applicable, the returned value’s data type. To supply a routine parameter value to a routine, simply name a compatible routine. Note that in this case you never specify any parameters, because you are not making a call here, but the called routine will do so “on behalf” of you. Specifying the routine’s name, and thus passing its address, is sufficient to achieve that.

Caveats
As a beginner, pointers are difficult to tame. Without experience, you will frequently observe (for you) “unexpected” behaviors. Some pitfalls are presented here.

-clause
Special care must be taken when using pointers in conjunction with a -clause. The expressions listed at the top of a -clause are evaluated once before executing any following statement. During the entire -statement the expressions using the “short” notation will actually use an invisible transient value. This speeds up execution, because the same value is not evaluated over and over again, but there is also a caveat in it.

Surprisingly, the long notation using an FQI can become invalid, while the short notation at first seems to be still valid. The following  demonstrates the issue: When you compile and run this, you will The  does actually use a “hidden (pointer) variable” and not. This variable’s value was evaluated one time at the top of the -clause. The compiler does not (and cannot) complain that  meanwhile became invalid. You are not making any assignments to the actually utilized hidden variable (i.&#8239;e. it is still considered bearing a valid value), thus there is no reason for complaints.
 * 1) notice that it prints anything but , but
 * 2) it should be rather astonishing that it still prints anything at all.

Limits
Memory is not an infinite resource. This has some grave implications.

There is no means to check whether any subsequent  will exhaust the finite resource memory. On multi-tasking OSs it is feasible that between the time you have queried the amount of free memory space and actually requesting additional memory, another  running at the same time has acquired memory so there is none, or not enough left for you. This kind of situation is known as. You need to simply in a make-or-break manner ask for more memory.

Tasks
Notes: