Page 1 of 2
Despite the fact that pointers have been long regarded as "dangerous" they are still deeply embedded in the way we do things.
The whole concept of a pointer is bound up in the idea of a memory location and its address. Despite the fact that pointers have been long regarded as "dangerous" they are still essential programming material.
The pointer has been transmuted into the "safe pointer" and more recently the managed reference - but it's still a pointer.
Let's look at the idea that is at the bottom of it all.
Pointers are natural
In assembly language you refer to a memory location by its address, for example 2000 refers to the memory location at address 2000. The confusion inherent in the idea of a pointer starts at this early stage of development.Are you talking about the thing itself i.e. the number 2000 or the thing stored at memory location 2000.
For example, does:
mean "with the value 2000" or "load the A register with the contents of address 2000"?
The ambiguity is usually solved by using an extra symbol if you mean the numeric value:
means "load the A register with the value 2000" and
means "load the A register with the contents of address 2000".
Once you know the rules it's easy enough but mistakes are still common - especially when you start using indirect addressing. Indirect addressing is where the value stored in a memory location is treated as an address to another memory location.
So for example, the command:
would mean load the A register with the value stored in the memory location whose address is stored in memory location 2000.
Well so were thousands of novice assembly language programmers. Redirection is where it just gets complicated enough for mistakes to be rule rather than the exception and redirection is something pointers allow you to do without thinking twice.
And once you have redirection you an easily invent re-redirection and so on - each one more difficult and dangerous than the last.
Pointers Pascal's way
When high level languages got going the idea of addresses and the whole idea of memory locations were hidden behind the facade of the variable.
There is no doubt that when you write something like
you are referring to the contents of SUM and TOTAL and there is no hint of addresses or redirection.
Many high level languages stop right there. But some don't - they re-invent the whole concept of addressing and indirection by way of pointer variables. That is, a variable that contains the address of another variable.
Pascal, for one, included pointers very early in its development and the pattern it adopted was used by C# and many other modern languages.
Of course Pascal being a strongly typed language means that pointers are typed as well. That is, a pointer can only point to a variable of one type. For example,
declares a to be a pointer to an integer and nothing but an integer.
When a pointer is first defined it contains the special value nil to mean that it isn't pointing to anything. To give it something to point at you have to use the procedure NEW in Pascal. The statement NEW(pointer) allocates enough storage for the type of data that the pointer is supposed to point at.
For example, NEW(a) would allocate enough storage for an integer and set a to point at it.
You can deallocate the storage that a pointer is pointing at using the complementary procedure DISPOSE. That is DISPOSE(a) frees the storage that a is pointing at for reuse. You can assign pointers but this is the only legal pointer operation.
For example, if a and b are integer pointers then
results in a and b pointing to the same area of storage.
To refer to the value actually stored in the area of memory that the pointer points at you have to use the ^ symbol in Pascal. This is often called the dereferencing operator.
So a is a pointer to an area of memory that holds an integer and a^ is the actual value stored there.
If you have followed the ideas so far you should be able to tell me the difference between:
The first makes a and b point at the same area of memory and the second one makes the area of memory that a points at hold the same value as the area of memory that b points at.
The most common error that beginners make is a:=b^, i.e. they try to assign the value pointed at to the pointer. Being strongly typed Pascal picks this error up at compile time.
Notice that even though Pascal is a high level language it is easy to fall into the habit of referring to areas of memory. The idea of an address and indirection is lurking just below the surface. But it is possible to describe all of this without such primitive concepts.
All you need to avoid introducing the pointer to "memory" is the idea of an anonymous variable, i.e. a variable without a name. In this way of explaining things NEW(a) creates an anonymous integer variable that a is set to point at. Notice that even though this description is slightly higher level it is still possible to make very strange errors using pointers to an anonymous variable.
For example, it is quite possible to lose an anonymous variable by overwriting all of the pointers to it!
Another favourite error is to DISPOSE of the memory that a pointer is pointing at but then still carry on using it - DISPOSE doesn't change the value of a pointer!
Using NEW and DISPOSE a Pascal programmer can create dynamic data structures such as strings, linked lists, stacks and so on. This ability to create such dynamic data structures is the main reason for the existence of pointers in programming languages. The only real alternative to using pointers is to provide advanced dynamic data structures as standard types.
For example, you can use pointers to program a variable length string of characters but modern languages make advanced and dynamic structure available without the use of pointers.