20 November 2016
There is a view that “true” programmers understand pointers (see Joel on Software’s article for an elaborate statement of this view). By pointer I mean an actual pointer, the kind that you can perform pointer arithmetic on, not simply a reference to an in-memory object (see this stack overflow post for a discussion of the difference). Armed with Kernighan and Ritchie’s The C Programming Language, in this post I explore two of C’s fundamental operators for the manipulation of pointers: & and * .
Kernighan and Ritchie define a pointer as follows:
A pointer is a variable that contains the address of a variable.
This address is essentially a number whose size depends on the architecture of the computer on which the program is running (on a 64 bit machine, an address has a size of 64 bits, or 8 bytes). As the diagram below shows, a pointer is a number in memory that is interpreted as holding the address of a value (it “points” to the value). The value can be any data type supported in C: an integer, a char, an array, a struct… The word value when applied to a pointer can be confusing. It can be used to denote the value of the address contained by the pointer variable, or the value that exists at that address (the value pointed to). In what follows, I will do my best to use the term value unambiguously.
In C a programmer can access and manipulate the value of the address held by a pointer. For instance, she can add one to this value, or divide it by two. She can then look up the data structure that exists at the memory address so computed. This is powerful, but also dangerous. An error in pointer arithmetic can lead to memory corruption and unexpected program crashes. Pointers are especially necessary in C because all function arguments are passed by value. This means that calling a function causes copies of the function’s arguments to be made. In order to avoid excessive copying, functions can be called with pointers to variables, rather than the actual (copied) values of these variables.
C offers two important operators for pointer manipulation: & and *. The * symbol is also used to declare a variable that holds a pointer. These operators enable the programmer to navigate between the value of the address and the data structure that exists at that address. The direction of this navigation is illustrated in the following diagram.
& takes us from value to address, while * takes us from address to value (this is known as dereferencing).
Some simple pointer manipulation:
Pointers and arrays:
Pointers can also point to values that are themselves pointers:
The following is an illustration of this final situation: