The Ongoing Mystery of the ** Variable

The ** notation can really make a beginning C programmer blanch. In fact, a lot of Java programmers probably fled from the C language just after the initial lesson on pointers. They’d turn to stone even to glance at a variable like **blorf. You don’t need to cower under a desk with those people.

Suppose an int pointer is declared as ptr:

int *ptr;

To use the pointer you have to initialize it, storing the address of some other int variable in the pointer, because:

A pointer is a variable that holds a memory location. Specifically it holds the address of another variable.

For example, variable i:

ptr = &i;

After that declaration in the code, pointer variable ptr holds the address of variable i. This process should be familiar to you if you read through one of my C programming books. Here’s some code you can chew on for review:

#include <stdio.h>

int main()
{
    int i;
    int *ptr;

    i = 4;      /* initialize i */
    ptr = &i;   /* initialize ptr */

    printf("i is %d\n",i);
    printf("&i is %p\n",&i);
    printf("*ptr is %d\n",*ptr);
    printf("ptr is %p\n",ptr);

    return(0);
}

The code shows how the pointer and variable are related. Here’s sample output:

i is 4
&i is 0028FF18
*ptr is 4
ptr is 0028FF18

Figure 1 shows the Watches window in Code::Blocks, which further demonstrates the equivalency between the variables. Pay attention to the far right column, which lists the variable types. See how both &i and ptr are basically the same type, int *, which means an integer pointer, or the memory location of an integer value.

Figure 1. The Watches window shows how the variable values and types are equivalent.

Figure 1. The Watches window shows how the variable values and types are equivalent.

Just for giggles, Figure 2 illustrates the bytes stored at memory location 0x28ff18. Integer values on my PC are stored in 32 bits, which is 4 bytes wide. You can see the value 4 stored in those four bytes, highlighted in the figure. (The value is stored backwards in memory, which is good for the processor, but not for humans reading a data dump.)

Figure 2. The value of variable i as stored in memory.

Figure 2. The value of variable i as stored in memory.

As with all variables, a pointer variable has a location in memory. To obtain that location, the unary & operator is used. The end result, the address of a pointer variable, is effectively a pointer-to-a-pointer.

Don’t let that sink in; just keep reading!

The address of a pointer variable is where those weird ** things come from. That’s because a variable with two unary * operators is a pointer-to-a-pointer.

Consider the following code, which adds a pointer-to-a-pointer variable, ptr2ptr, to the original code listed earlier:

#include <stdio.h>

int main()
{
    int i;
    int *ptr;
    int **ptr2ptr;

    i = 4;
    ptr = &i;
                /* initialize ptr2ptr: */
    ptr2ptr = &ptr;

    printf("i is %d\n",i);
    printf("&i is %p\n",&i);
    printf("*ptr is %d\n",*ptr);
    printf("ptr is %p\n",ptr);
                /* new stuff here: */
    putchar('\n');
    printf("&ptr is %p\n",&ptr);
    printf("ptr2ptr is %p\n",ptr2ptr);
    printf("*ptr2ptr is %p\n",*ptr2ptr);

    return(0);
}

The ptr2ptr variable is initialized at Line 12. It’s assigned the address of the ptr pointer. A ** variable like ptr2ptr holds the address of a pointer. In this code that pointer is an int pointer, *ptr.

Here’s the program output, along with my comments (in red) explaining the last three lines:

i is 4
&i is 0028FF18
*ptr is 4
ptr is 0028FF18

&ptr is 0028FF14      The address of variable ptr in memory
ptr2ptr is 0028FF14   Also the address of variable ptr in memory
*ptr2ptr is 0028FF18  The address of variable i in memory

The memory address of ptr is fetched by using the & operator. In the above output, that location is 0x28FF14.

Variable ptr2ptr stores the address of variable ptr. You can see that by the second to last line of output. Both lines display 0x28FF14.

At the last line, the contents of variable ptr2ptr when used with the unary * operator are the same as the contents of the ptr variable, the address of variable i.

The final step is to add the following line to the code, just after the last printf() statement above the return statement:

printf("**ptr2ptr is %d\n",**ptr2ptr);

Compile and run on your own. Doing so will help you better understand what’s going on, or at least take you one step closer. I’ll explain more in next week’s Lesson.

Leave a Reply