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
.