Pointers to pointers in C

Pointers seem to be the most confusing part about C. It takes a while to fully understand them. As soon as you start feeling what they are about you stumble on a pointer to a pointer. Technically not that much changes but, again, it takes a while to create a solid understanding of what’s going on. As they say: you don’t understand something if you can’t explain it in a simple way.

Let me take a stab at pointers.

Lets look at a simple pointer:

int a = 10;
int* p = &a;
...

A variable, with value of 10 has been created on the stack and a pointer p points to it. Memory layout of this situation would look like so:

  • a is a way to get the value
  • &a is a way to get the address of where the value 10 is stored
  • p gets you the address of the value 10
  • *p fetches the value that’s stored under that address
  • &p returns an address of where the pointer is stored

That’s basics of pointers. Pointers to pointers work the same way. For me, a pretty specific situation, that required some thought, was when you pass a pointer to a function in order to point it to some other address.

static int A = 1;
static int B = 2;

void point_to_A(int** p)
{
  *p = &A;
}

void point_to_B(int* p)
{
  p = &B;
}

int main()
{
  int* k = NULL;
  point_to_B(k);       /* k stays unchanged */
  point_to_A(&k);      /* k points to A */
}

This code creates two global variables. In the main function a pointer has been created.

First lets look what happens when you call point_to_B:

  • a new pointer int* p is created on the stack
  • that pointer points to the same address as the passed k pointer. This is the important part. In the scope of the point_to_B function you don’t have an access to the k pointer. You just use a new pointer that points to the same memory address. That’s why passing things via pointers allows us to modify the original value.
  • the new pointer p gets binded to the B’s value with p = &B
  • the function ends and cleans up the p pointer from the stack

Lets look at the point_to_A, which allows us to actually modify pointer and point it to something else.

  • a new pointer to a pointer int** p is created on the stack
  • that pointer points to the address where pointer k lives. That means we can modify the contents of that memory. For a pointer, contents of its memory is that address it points to.
  • the address of the variable A gets saved in the p’s value.
  • the functions ends and cleans up the p pointer from the stack.
...

A good way to look at this is that function’s arguments become new variables on the stack. In the first point_to_B function that means that, in the scope of the function, you get a new pointer p which just points to the same memory as the original pointer k. In this situation you can’t modify the pointer itself. You know nothing about the original pointer, except that the new pointer p points to the same memory.

In the second case you actually know where the original pointer lives (sounds spooky). You have its address. If you have something’s address you can change its contents. For a pointer, contents happens to be the address of the memory it points to. Changing that contents changes what it points to.

Nothing here should be surprising. It only reinforces the idea of memory access in C. If you have an address of variable, you can modify it. That’s all there is to it ;)