Multiple indirection generally occurs in the following scenarios: writing to a parameter of pointer type, and building an N-dimensional array by pieces.
Writing to a parameter of pointer type
For any function parameter of type T
, if you want the function to modify the value of the parameter and have that new value reflected in the caller, you must pass a pointer:
void foo( T *ptr )
{
*ptr = new_value(); // writes new value to thing pointed to by ptr
}
void bar( void )
{
T var;
foo( &var ); // writes new value to var
}
The expression *ptr
in foo
refers to the same object in memory as var
in bar
, so writing to *ptr
is equivalent to writing to var
.
If T
is a pointer type Q *
, then you wind up with a pointer to a pointer:
void foo( Q **ptr )
{
*ptr = new_value(); // writes new value to thing pointed to by ptr
}
void bar( void )
{
Q *var;
foo( &var ); // writes new value to var
}
In this second case, you want to modify the pointer value stored in var
. Again, both *ptr
and var
refer to the same memory location, but this time, var
contains a pointer value. You could replace Q
with R *
, giving
void foo( R ***ptr )
{
*ptr = new_value(); // writes new value to thing pointed to by ptr
}
void bar( void )
{
R **var;
foo( &var ); // writes new value to var
}
The semantics are the same in all three cases; we write a new value to var
through the expression *ptr
; it's just the type of var
is a pointer type, meaning the type of ptr
must be a pointer type with one more level of indirection.
Building an N-dimensional array by pieces
Suppose you want to allocate an N
xM
array of T
, but you don't know the values of N
or M
at compile time. One approach is to declare a pointer to a pointer, then allocate an array of pointers to it:
T **arr; // arr will point to an NxM array of T
size_t n, m;
/**
* get values for n and m
*/
arr = malloc( sizeof *arr * n ); // allocate N objects of type T *
if ( arr )
{
for ( size_t i = 0; i < n; i++ )
{
arr[i] = malloc( sizeof *arr[i] * m ); // allocate M objects of type T
if ( arr[i] )
{
for ( size_t j = 0; i < m; i++ )
{
arr[i][j] = some_value();
}
}
}
}
The same general mechanism can be applied for higher-dimensioned arrays:
T ***arr3;
...
arr3 = malloc( sizeof *arr3 * n );
...
arr3[i] = malloc( sizeof *arr3[i] * m );
...
arr3[i][j] = malloc( sizeof *arr3[i][j] * k );
There are a few other scenarios where you see multiple indirection, but those are the two main ones.
It's rare in practice to see more than three levels of indirection, though.
n
. You dereference it once you get the pointer it was pointing to, dereference it twice you get the object pointed to by the pointerptr_ptr
is pointing to.