Pointers
In my opinion pointers and arrays cause by far the most confusion
and program failures. The difficulty comes when trying to visualise
how pointers and arrays are handled by the compiler, essentially,
what is a pointer ?
Variables in general
Before going on to talk specifically about pointers let us first
look at variables in general and consider how they are handled by
compilers. A variable is a name that represents a location in memory
that can be used to store some data in a program. We will refer to that
location in memory as the address of the variable. In general the
address is only known when the program is running, so we use the name
of the variable in the program source code to represent the unknown
address.
Let us declare 2 numeric variables and see what would happen if a compiler
read the code:
int iVar1;
int iVar2;
The compiler ensures that sufficient memory space is reserved for the
variables in order that each will be able to hold a numeric value.
So, when statements such as:
iVar1 = 2;
are encountered by the compiler, it would generate instructions, that
when executed, use the address of the variable, iVar1, to find
where the reserved memory space is, and then store the data, whatever is
on the right hand side of the assignment operator, in this case the numeric
value 2, in that location.
When the name of a variable is used on the right hand side of an assignment
statement, such as:
iVar2 = iVar1;
the intention is to copy the value stored in the variable on the right
and store it in the variable on the left. To do this the address of the
variable on the right is used to retrieve the value stored there, 2
in this case, and then the address of the variable on the left is used to
find the memory space into which the retrieved value (2) is to be
stored.
It can be seen then, that, without the programmer having to do anything
special, when a variable name is used within a program statement, the
compiler treats it as an instruction to access a memory location. The
programmer does not have to know, or determine, the address of that memory
location themselves, it is handled directly by the compiler.
So to briefly sum up, using simple variables in program code will cause
the compiler to generate instructions to access a memory location, the
address of which is known only at the time the program is run, and
perform an action using the data stored at the address. Pointers are
a fairly simple extension of this memory address concept. A pointer can
also be considered as a simple variable, but not one that contains straight
forward numeric data, like the ints above, but rather one that
contains a memory location address: the address of a variable.
Pointer variables
Let us now declare a pointer variable and see what happens:
int *piVar1;
This time the compiler will reserve enough memory in order that the
address of an int can be stored. The only difference
in the declaration of an int and a pointer to an int
is the * character in front of the variable name.
The variable declared above, piVar1, should not be used until
an address is stored in it, because a newly created pointer variable
does not contain a sensible address. In order to store a sensible
address we need to find out the address of another variable. The only
type of address we can safely store in piVar1 is that of an
int because it was specifically declared as a pointer to
an int.
The following statement will store a usable address in piVar1:
piVar1 = &iVar1;
The & character is used to instruct the compiler to
use the address of the variable, iVar1 in this case, as the
value to store in piVar1, rather than using the address in order
to access memory to get the value to store.
Once the address of a variable is stored in a pointer it is possible
to use that stored address in place of the variable name. For example
the following 2 statements are exactly equivalent in functionality:
iVar2 = *piVar1;
iVar2 = iVar1;
The * character in the first statement is used to tell
the compiler that, once it has retrieved the value stored at the memory
location for piVar1, it should use that retrieved value in order
to access memory once again, to get the actual value to store in
iVar2. Therefore, because piVar1 contains the address
of iVar1, accessing memory again using this value actually gets
the value stored in iVar1, in this case the numeric value
2. So to get the data to store in iVar2 two memory
accesses are required:
- to get the value in piVar1, an address
- to use this address to get the data to store
This holds true for all types of pointer variable and it can be seen
that we are indirectly accessing the pointed to variable.
The address a pointer holds is effectively a reference to another
variable. Therefore, when using the pointer variable to access the
referenced variable, by prefixing the pointer variable name with
*, we can say that the pointer is being de-referenced.
|