Pointers I
Pointers are a very powerful, but primitive facility contained in the C language. Pointers are a throwback to the days of low-level assembly language programming and as a result they are sometimes difficult to understand and subject to subtle and difficult-to-find errors. Still it has to be admitted that pointers are one of the great attractions of the C language and there will be many an experienced C programmer spluttering and fuming at the idea that we would dare to refer to pointers as 'primitive'!
A variable is an area of memory that has been given a name.
For example:int x;
is an area of memory that has been given the name x. The advantage of this scheme is that you can use the name to specify where to store data.
For example:x=10;
is an instruction to store the data value 10 in the area of memory named x. The variable is such a fundamental idea that using it quickly becomes second nature, but there is another way of working with memory.
A pointer is a variable that stores this location of memory. In more fundamental terms, a pointer stores the address of a variable. A pointer has to be declared just like any other variable - remember a pointer is just a variable that stores an address.
For example:int *p;
is a pointer to an integer. Adding an asterisk in front of a variable's name declares it to be a pointer to the declared type. The asterisk applies only to the single variable name that it is in front of, so:
int *p , q;declares a pointer to an int and an int variable, not two pointers.
Once you have declared a pointer variable you can begin using it like any other variable, but in practice you also need to know the meaning of two new operators: & and *. The & operator returns the address of a variable.
For example:int *p , q;
declares p, a pointer to int, and q an int and the instruction:
p=&q;
stores the address of q in p. The second operator * is a little more difficult to understand. If you place * in front of a pointer variable then the result is the value stored in the variable pointed at. That is, p stores the address, or pointer, to another variable and *p is the value stored in the variable that p points at.
The * operator is called the de-referencing operator and it helps not to confuse it with multiplication or with its use in declaring a pointer.
Basic Ideas:
To declare a pointer add an * in front of its name.
To obtain the address of a variable us & in front of its name.
To obtain the value of a variable use * in front of a pointer's name.
Now see if you can work out what the following means:
int *a , b , c;b = 10;
a = &b;
c = *a;
Firstly three variables are declared - a (a pointer to int), and b and c (both standard integers). The instruction stores the value l0 in the variable b in the usual way. The first 'difficult' instruction is a=&b which stores the address of b in a. After this a points to b. Finally c = *a stores the value in the varable pointed to by a in c. As a points to b, its value i.e. 1O is stored in c. In other words, this is a long winded way of writing
c = b;Swap Shop function swap(int a , int b);
{
int temp;
temp = a;
a = b;
b = temp;
}
the only complication being the need to use a third variable temp to hold the value of a while the value of b overwrites it. That is, when you use swap(a,b) function the values in a and b are passed into the function swap via the parameters and any changes that are made to the parameters do not alter a and b back in the main program. The function swap does swap over the values in a and b within the function, but doesn't do so in the main program.
The solution to this very common problem is to pass not the values stored in the variables, but the addresses of the variables. The function can then use pointers to get at the values in the variables in the main program and modify them. That is, the function should be:
function swap(int *a , int *b);{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
For example, calling swap as swap(a,b) instead of swap(&a,&b) will result in two arbitrary areas of memory being swapped over, usually with the result that the entire system, not just your program, crashes. The need to pass an address to a function also explains the difference between the two I/O functions that we have been using since the beginning of this course. printf doesn't change the values of its parameters so it is called as printf("%d",a) but scanf does, because it is an input function, and so it is called as scanf("%d",&a).
Pointers And ArraysIn C there is a very close connection between pointers and arrays. In fact they are more or less one and the same thing! When you declare an array as:
int a[10];you are in fact declaring a pointer 'a' to the first element in the array. That is, 'a' is exactly the same as &a[0]. To be more precise, a[i] is exactly equivalent to *(a+i) i.e. the value pointed at by a + i . In the same way *(a+ 1) is the same as a[1] and so on.
In practice you don't have to worry about how much storage a pointer's base type takes up. All you do need to remember is that pointer arithmetic works in units of the data type that the pointer points at. Notice that you can even use ++ and -- with a pointer, but not with an array name because this is a constant pointer and cannot be changed.
An array's name is a constant pointer to the first element in the array that is a==&a[0] and *a==a[0]. The view of it as an array is the more sophisticated and the further away from the underlying way that the machine works. The view as a pointer and pointer arithmetic is more primitive and closer to the hardware. One final point connected with both arrays and functions is that when you pass an entire array to a function then by default you pass a pointer. This allows you to write functions that process entire arrays without having to pass every single value stored in the array - just a pointer to the first element.
For example:void randdat(int *pa , int n)
{
for (pa = 0 ; pa < n ; pa++ ) *pa = rand()%n + 1;
}
The pointer pa is supposed to point to the first element of the array, but the for loop sets it to zero and then increments it though a series of memory locations nowhere near the array. A lesser error is to suppose that n-1 is the correct final value of the array pointer.