Lecture 20: Pointers


Pointer

A pointer is a special type of variable. In itself it contains no useful information. It is only an address to what (might) contain useful information.
 A pointer contains the address of a place in memory 

This is like keeping the address of an appartment in my addressbook. It is only an address and nothing more.
To declare a pointer we can use the following syntax:
  Var p: pointer;


Pointer instructions

There are two pointer operations in PASCAL
 
 
 @x or Addr(x) returns a pointer to variable x
 p^ is what pointer p points to 

 
In the example on the left, x is a variable of type real that has a value of 3.0. When we want the pointer p to point to this variable, we can use
  p := @x;
or
  p := Addr(x);
The value of p is now a memory address, namely the address that contains the variable x. To show the contents of the memory of what p points to, we might think that we can do this with
  WriteLn(p^);
There is only one thing wrong with this. The compiler only knows that p is of type pointer. When we run the program we let it point to a certain place in memory, but the program doesn't know what (type of information) the pointer is pointing to. Picture the following situation. A pointer p points to a place in memory. If it is pointing to a byte, the value is different than if it is pointing to an integere or a word. In the example below, p^ pointing to a byte is 129 (binary: 10000001), while the same p^ pointing to the same place in memory, but pointing to a word is equal to 25473 (binary: 0110001110000001), or p^ pointing to a longint (4 bytes, 32 bits) will give 743924609 (binary: 00101100010101110110001110000001). (Note that in Intel-processor-based computers numbers are stored with their lowest value bit [LSB=least significant bit] first).

Therefore, we have to specify the type the pointer is pointing at. For that we have to go back to the declaration of the pointer. Instead of just using 'pointer' for the type, we will specify what kind of variable the pointer will point to:


Declaring a pointer

To declare a pointer we can use the following forms:
 
 Var p: pointer; 
 Var p: ^type;

The first form declares a general pointer, without specifying what type of data it will point to.
The second form also specifies the type of data it points to. For type we can use any type we have learned. From the simple variables (integer, real, etc) to the complicated types (record, array), to combinations of these (arrays of records, records of arrays).
Examples:
  Var byteptr:  ^byte;
      wordPtr:  ^word;
      real6arrayptr: ^array[1..6] of real;

Now let's see an example to show check if we have everything under control. We are going to create a pointer of type 'pointing to a word', and let it point to a word:

  Var wordptr: ^word;
      w: word;

  begin
     (* assign a value to the word *)
    w := 25473;
     (* let a 'pointer to word' point to our word *)
    wordptr := Addr(w);
     (* show the contents of the memory wordptr points to *)
    WriteLn(wordptr^);
  end.

output:
  25473

Now let's see a more complicated example. We are going to create a pointer of type 'pointing to a byte', and let it point to our word:

  Var byteptr: ^byte;
      w: word;

  begin
     (* assign a value to the word *)
    w := 25473;
     (* let a 'pointer to word' point to our word *)
    byteptr := Addr(w);
     (* show the contents of the memory wordptr points to *)
    WriteLn(byteptr^);
  end.

output:
 129

This shows that we have to be careful what our pointer points to. The value depends on the type!


Why?


Why use pointers? There are several reasons to use pointers instead of normal variables. The most important ones are
 
  • Rapidez
  • Flexibilidade

Speed: Imagine you write a procedure that has an array as parameter. Every time the program calls the procedure, the entire array has to be copied in memory and the procedure executed. If, instead of telling the procedure the value of every element of the array, it would be much faster to only tell the address of the array. This means copying only a single variable (a pointer is just 4 bytes in Intel computers).
 

PROGRAM TestSpeed;

Type ra = array[1..1000] of real; 
Var r: ra;
    i: longint;

PROCEDURE SlowProc(a: ra);
begin
  a[1] := 1.0;
end;

begin
  for i := 1 to 4000000 do
    SlowProc(r)
end.

PROGRAM TestSpeed;

(* define an array and a pointer to
  that arrray: *)
Type ra = array[1..1000] of real;
     rap = ^ra;
Var r: ra;
    i: longint;

PROCEDURE FastProc(a: rap);
begin
  (* a is a pointer to an array *)
  (* a^ is what it points to, the *)
  (* the array. a^[1] is the first *)
  (* element of that array *)
  a^[1] := 1.0;
end;

begin
  for i := 1 to 4000000 do
    FastProc(@r)
   (* pass only a pointer to *)
   (* the procedure *) 
end.


execution time on a Pentium II 450 MHz:
115 s.


execution time on a Pentium II 450 MHz:
1 s.

(In fact, the program on the right does the same as a program that passes the array by reference (see lecture 15). PROCEDURE SlowProc(Var a: ra);  is also fast. Passing by reference means that a pointer is passed to the procedure.)

Flexibility: If, at the beginning of the program we do not know yet how many variables we need we would have to reserve space for all possible eventualities. If we want to write a program that calculates the first N prime numbers, with N given by the user, we would have to declare an array of maximum size to be sure that we can fit the users request in it. Something like this:
  Var prime: array[1..10000000] of longint;
With this we would completely occupy the memory of the computer. Nothing else can run anymore. Much nicer would be if we could declare the array (the variables) dynamically so that we only use memory if we really need it. With pointers this is easily possible.

The pointers and the idea of dynamic creation of variables also lies at the basis of object-oriented programming, which is the type of programming of every modern computer language. Object oriented programming is outside the scope of this lecture, though.


NIL

A pointer that is not pointing to anything has the value NIL. NIL is a predefined constant in PASCAL.

Quick Test

To test your knowledge of what you have learned in this lesson, click here for an on-line test.

Peter Stallinga. Universidade do Algarve, 23 Abril 2002