Here’s a scary thing for most people: **blorf
. No, not the name blorf, although it’s one of my favorite made-up words. What drives programmers insane — and all programmers, not just C programmers — are those double disaster asterisks.
A pointer is a variable that holds a memory location, specifically the address of another variable.
The pointer-to-a-pointer thing is confusing, I confess, but it doesn’t need to be. As an example, consider the following code, which uses a pointer array months
to create a buncha strings:
#includeint main() { char *months[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; int x; for(x=0;x<12;x++) printf("%s\n",months[x]); return(0); }
An array of pointers is created at Line 5. It’s a common shortcut used by many programmers who need an array of strings. It’s not really an array of strings, however: It’s a list of 12 memory locations, each of which is the starting address of a string stored in memory.
Figure 1 is a screenshot from the Code::Blocks debugger. It illustrates how the memory locations, or pointer values, are stored in the array.
As you can see in Figure 1, each element of the array is an address, a memory location. The first element, months[0]
, holds the address 0x403024
, which references the string “January.”
The code displays the strings by using the printf() function at Line 12, courtesy of the for loop at Line 11. Simple, standard fare.
Well, it looks simple because array notation is used. Yet, months
is really a list of addresses, pointers. Just like the *argv[]
argument for the main() function, it can also be written as **months
.
Please do not flee in terror!
The **months
construction works because months
is a pointer and it references other pointers. An array is pretty-much a gussied up pointer. Therefore, the months
variable itself references the starting address of a string. That’s how it can be used to display the strings; months
references each string’s starting address.
Let that sink in as you view this next code sample. Line 12 (the printf() function) substitutes a pointer for the array notation used in the original example:
#includeint main() { char *months[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; int x; for(x=0;x<12;x++) printf("%s\n",*(months+x)); return(0); }
The variable *(months+x)
walks through the list of addresses stored in the months
array. It starts with 0x403024
(from Figure 1) and then goes to 0x40302c
, and so on.
Now you can’t use **months
to declare an array of strings. That’s because an array must be declared by using array notation. So although **months
and *months[]
are equivalent elsewhere in the code, **months
isn’t an array and cannot be used to declare one. To review:
**months
is a pointer variable that holds the value of another pointer variable.
*months[]
is a pointer variable that references an array of pointer variables.
To help illustrate how this nonsense applies you can bring in another pointer-to-a-pointer variable, a second dratted **
thing, such as the variable **blorf
.
The following code demonstrates how **months
and *months[]
are equivalent:
#include <stdio.h> int main() { char *months[] = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; int x; char **blorf; /* here is the bastard */ blorf = months; for(x=0;x<12;x++) printf("%s\n",*(blorf+x)); return(0); }
Pointer variable **blorf
is declared at Line 10. It’s a pointer-to-a-pointer variable, as shown by the dang double *
operators.
In Line 12, variable blorf
is initialized to variable months
. Both variables are of the same type — **blorf
and **months
, two char pointer-to-pointer variables — so the &
(address-of) unary operator isn’t needed. (Both variable already hold memory locations.) After that, blorf
can substitute for months
, which it does at Line 14 to display the array of strings.
Confused? Probably. Don’t sweat it. This kind of notation is rare. Despite that rarity, I stubbornly continue this pointless pointer-to-pointer discussion in next week’s Lesson.