Up to this point in the discussion, we have considered variables as containers for our data, but it is important to remember that variables simply represent memory locations in the computer. One of the most powerful features of C as a language is the ability to directly manipulate the memory of the computer system at a very low level. A pointer is the C term for a variable that stores a memory address; in essence, it "points" to that address. Pointers can be used to modify data, to share access to variables between different functions, or to build more complex data structures.

First consider the case of variables passed as arguments to functions. In any programming language, there are two ways to do this. The function could make a copy of the variable and it's contents being passed in. This creates a new copy of the variable and is referred to typically as "pass by value". In this method, when the function changes it's local variable, the program calling the function never sees the change in it's (original) copy. This is frequently useful, but, if you want the function to operate on a large array that the main program will use again, you may want to make the changes the function makes to the array visible without copying all the values into the function, and then later back out again.

The way a program handles this is to pass arguments to a function through what is known as "pass by reference". In this case, rather than making a copy of the variable, you simply pass it's memory address to the function. The Fortran programming language uses pass by reference. In C, you have the option to do either. The normal behavior of C function is to do pass by value. However, if you wish to do pass by reference, you simply pass in a pointer to the variable (it"s address) as the argument. The called function receives a copy of the pointer, but this copy still has the address of the original variable (i.e. the copy points to the same thing as the original).

The C library function scanf() is a good example of when pointers may be used. When called, scanf() takes a value from the input (typically the keyboard) and places it into a variable passed as an argument to scanf(). Changing a copy of the variable would be useless, since you called scanf() to find out the value typed! So, when using scanf(), you always provide it a pointer to a variable; the address of the memory location into which you would like it to scan the data. Pointers can be declared like any other variables, but two special operators are used to manipulate memory addresses. Using * before a pointer means "the value store at" whereas using & on any variable means "the address of" as is demonstrated in the following example:

In line 01 we declare an integer pointer named p, this is only a declaration and this pointer is not "pointing" at any specific area of memory. Line 02 initializes a variable named q and sets it's value to 5. Line 03 uses the & to assign p the "address of variable q". Line 04 sets the "value of the integer pointed to by p" to 10, and since p is pointing to q's memory, q now has the value of 10. This is just an example of what pointers can do. The usefulness of pointers is that they allow the programmer to alter a variable in a function, as well as assist the programmer in achieving optimal speeds, clarity and simplicity.

Example: pass by reference

Line 01 includes some standard library function prototypes for input and output, including printf() (see Line 10).

Line 03 is the function prototype, this time taking a pointer as input.

Line 09 makes the call to the function square_num and passes it the "address of variable p" using the &.

Skip down to the function starting on Line 14: The function takes a pointer as input and names it num.

Line 16 squares the value of num by multiplying it by itself and assigning the value back to the memory pointed to by the variable num. Remember that using the * gives the value that the pointer is pointing at.

Line 10 prints the value of p to the screen, which it has now changed to be the square of p.

You can also do arithmetic on pointers as you can with integer variables. However, you must be careful to keep track of whether you are doing arithmetic on the memory address (which changes where the pointer points), or on the value to which the pointer points. Pointer arithmetic is often used in conjunction with arrays (arrays themselves are simply pointers to a set of memory locations. Consider the following example:

At the end of this set of statements, we have set A[1] equal to 3. Line 4 sets p to point to the start of the array A. In line 5, the pointer itself is incremented, which causes it to point to A[1]. In line 6, we increment what p pointed to, causing A[1] to change from 2 to 3.

Working with pointers can be very confusing for a beginner. However, they are also very useful in C programming and usually lead to more compact and efficient code. With pointers we can effectively return more than one thing from a function, and one must understand pointer semantics if one plans to use arrays effectively.

 
©   Cornell University  |  Center for Advanced Computing  |  Copyright Statement  |  Inclusivity Statement