An Array of Pointers

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:

#include 

int 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.

Figure 1. How the months array looks in memory.

Figure 1. How the months array looks in memory.

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:

#include 

int 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.

Leave a Reply