The purpose of a pointer is to save the address of a specific variable. Then the memory structure of following code should look like:
int a = 5;
int *b = &a;
Pointers are abstractions of memory addresses with additional type semantics, and in a language like C type matters.
First of all, there's no guarantee that int * and int ** have the same size or representation (on modern desktop architectures they do, but you can't rely on it being universally true).
Secondly, the type matters for pointer arithmetic. Given a pointer p of type T *, the expression p + 1 yields the address of the next object of type T. So, assume the following declarations:
char *cp = 0x1000;
short *sp = 0x1000; // assume 16-bit short
int *ip = 0x1000; // assume 32-bit int
long *lp = 0x1000; // assume 64-bit long
The expression cp + 1 gives us the address of the next char object, which would be 0x1001. The expression sp + 1 gives us the address of the next short object, which would be 0x1002. ip + 1 gives us 0x1004, and lp + 1 gives us 0x1008.
So, given
int a = 5;
int *b = &a;
int **c = &b;
b + 1 gives us the address of the next int, and c + 1 gives us the address of the next pointer to int.
Pointer-to-pointers are required if you want a function to write to a parameter of pointer type. Take the following code:
void foo( T *p )
{
*p = new_value(); // write new value to whatever p points to
}
void bar( void )
{
T val;
foo( &val ); // update contents of val
}
This is true for any type T. If we replace T with a pointer type P *, the code becomes
void foo( P **p )
{
*p = new_value(); // write new value to whatever p points to
}
void bar( void )
{
P *val;
foo( &val ); // update contents of val
}
The semantics are exactly the same, it's just the types that are different; the formal parameter p is always one more level of indirection than the variable val.