|
|
|
|
|
|
|
|
|
|
|
Initialization of pointers
|
|
|
Something to be wary of with pointer variables is the way that they are initialized. It is incorrect, logically, to initialize pointers in a declaration. A compiler will probably not prevent this however because there is nothing incorrect about it as far as syntax is concerned. |
|
|
|
|
|
Think about what happens when the following statement is written. This statement is really talking about two different storage places in the memory: |
|
|
|
|
|
int *a = 2; |
|
|
|
|
|
First of all, what is declared is a pointer, so space for a `pointer to int' is allocated by the program and to start off with that space will contain garbage (random numbers), because no statement like |
|
|
|
|
|
a = &someint; |
|
|
|
|
|
has yet been encountered which would give it a value. It will then attempt to fill the contents of some variable, pointed to by a, with the value 2. This is doomed to faliure. a only contains garbage so the 2 could be stored anywhere. There may not even be a variable at the place in the memory which a points to. Nothing has been said about that yet. This kind of initialization cannot possibly work and will most likely crash the program or corrupt some other data. |
|
|
|
|
|
Pointer manipulation
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Pointers and arrays
|
|
|
To fully understand the workings of C you must know that pointers and arrays are related. |
|
|
|
|
|
An array is actually a pointer to the 0th element of the array. Dereferencing the array name will give the 0th element. This gives us a range of equivalent notations for array access. In the following examples, arr is an array. |
|
|
|
|
|
Array Access
|
Ponter Equivalent
|
arr[0]
|
*arr
|
arr[2]
|
*(arr + 2)
|
arr[n]
|
*(arr + n)
|
|
|
|
|
|
|
There are some differences between arrays and pointers. The array is treated as a constant in the function where it is declared. This means that we can modify the values in the array, but not the array itself, so statements like arr ++ are illegal, but arr[n] ++ is legal. |
|
|
|
|
|
Since an array is like a pointer, we can pass an array to a function, and modify elements of that array without having to worry about referencing and de-referencing. Since the array is implemented as a hidden pointer, all the difficult stuff gets done automatically. |
|
|
|
|
|
A function which expects to be passed an array can declare that parameter in one of two ways. |
|
|
|
|
|
int arr[]; or int *arr; |
|
|
|
|
|
Either of these definitions is independent of the size of the array being passed. This is met most frequently in the case of character strings, which are implemented as an array of type char. This could be declared as char string[]; but is most frequently written as char *string; In the same way, the argument vector argv is an array of strings which can be supplied to function main. It can be declared as one of the following. |
|
|
|
|
|
chat **argv; or char *argv[]; |
|
|
|
|
|
Don't panic if you find pointers confusing. While you will inevitably meet pointers in the form of strings, or as variable arguments for functions, they need not be used in most other simple types of programs. |
|
|
|
|
|
Pointer arthmetic
|
|
|
You can perform a limited number of arithmetic operations on pointers. These operations are: |
|
|
|
|
|
- Increment and decrement
- Addition and subtraction
- Comparison
- Assignment
|
|
|
|
|
|
The increment (++) operator increases the value of a pointer by the size of the data object the pointer refers to. For example, if the pointer refers to the second element in an array, the ++ makes the pointer refer to the third element in the array. |
|
|
|
|
|
The decrement (--) operator decreases the value of a pointer by the size of the data object the pointer refers to. For example, if the pointer refers to the second element in an array, the -- makes the pointer refer to the first element in the array. |
|
|
|
|
|
You can add an integer to a pointer but you cannot add a pointer to a pointer. |
|
|
|
|
|
If the pointer p points to the first element in an array, the following expression causes the pointer to point to the third element in the same array: |
|
|
|
|
|
p = p + 2; |
|
|
|
|
|
If you have two pointers that point to the same array, you can subtract one pointer from the other. This operation yields the number of elements in the array that separate the two addresses that the pointers refer to. |
|
|
|
|
|
You can compare two pointers with the following operators: ==, !=, <, >, <=, and >=. |
|
|
|
|
|
Pointer comparisons are defined only when the pointers point to elements of the same array. Pointer comparisons using the == and != operators can be performed even when the pointers point to elements of different arrays. |
|
|
|
|
|
You can assign to a pointer the address of a data object, the value of another compatible pointer or the NULL pointer. |
|
|
|
|
|
Pointers to functions
|
|
|
Let's now consider pointers to functions as opposed to variables. This is an advanced feature which should be used with more than a little care. The idea behind pointers to functions is that you can pass a function as a parameter to another function! This seems like a bizarre notion at first but in fact it makes perfect sense. |
|
|
|
|
|
Pointers to functions enable you to tell any function which sub-ordinate function it should use to do its job. That means that you can plug in a new function in place of an old one just by passing a different parameter value to the function. You do not have to rewrite any code. In machine code circles this is sometimes called indirection or vectoring. |
|
|
|
|
|
When we come to look at arrays, we'll find that a pointer to the start of an array can be found by using the name of the array itself without the square brackets []. For functions, the name of the function without the round brackets works as a pointer to the start of the function, as long as the compiler understands that the name represents the function and not a variable with the same name. So--to pass a function as a parameter to another function you would write |
|
|
|
|
|
function1(function2); |
|
|
|
|
|
If you try this as it stands, a stream of compilation errors will be the result. The reason is that you must declare function2() explicitly like this: |
|
|
|
|
|
int function2(); |
|
|
|
|
|
If the function returns a different type then clearly the declaration will be different but the form will be the same. The declaration can be placed together with other declarations. It is not important whether the variable is declared locally or globally, since a function is a global object regardless. What is important is that we declare specifically a pointer to a function which returns a type (even if it is void). The function which accepts a function pointer as an argument looks like this: |
|
|
|
|
|
1 function1 (a)
2 int (*a)();
3 {
4 int i;
5 i = (*a)(parameters);
6 }
You could download file pointer_fun.c here
|
|
|
|
|
|
This declares the formal parameter a to be a pointer to a function returning a value of type int. Similarly if you want to declare a pointer to a function to a general type typename with the name fnptr, you would do it like this: |
|
|
|
|
|
typename (*fnptr)(); |
|
|
|
|
|
Calling a function by pointer
|
|
|
Given a pointer to a function how do we call the function? The syntax is this: |
|
|
|
|
|
variable = (*fnptr)(parameters); |
|
|
|
|
|
An example let us look at a function which takes an integer and returns a character. |
|
|
|
|
|
int i; |
|
|
char ch, function(); |
|
|
|
|
|
Normally this function is called using the statement: |
|
|
|
|
|
ch = function(i); |
|
|
|
|
|
but we can also do the same thing with a pointer to the function. First define |
|
|
|
|
|
1 char function();
2 char (*fnptr)();
3
4 fnptr = function;
5
6 //then call the function with
7
8 ch = (*fnptr)(i);
You could download file pointer1.c here
|
|
|
|
|
|
A pointer to a function can be used to provide a kind of plug-in interface to a logical device, i.e. a way of choosing the right function for the job. |
|
|
|
|
|
1 void printer(),textscreen(),windows();
2
3 switch (choice)
4 {
5 case 1: fnptr = printer;
6 break;
7 case 2: fnptr = textscreen;
8 break;
9 case 3: fnptr = windows;
10 }
11
12 output(data,fnptr);
You could download file pointer2.c here
|
|
|
|
|
|
This is the basis of `polymorphism' found in object oriented languages: a choice of a logical (virtual) function based on some abstract label (the choice). The C++ language provides an abstract form of this with a more advanced syntax, but this is the essence of virtual function methods in object oriented languages. |
|
|
|
|
|
BEWARE! A pointer to a function is an automatic local variable. Local variables are never initialized by the compiler in C. If you inadvertently forget to initialize the pointer to a function, you will come quickly to grief. Make sure that your pointers are assigned before you use them. |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|