Search code examples
cpointers

passing a pointer to a pointer in C


Compiling:

#include <stdlib.h>


void f(int ** v)
{
}

int main()
{
    int v[2][3];
    f(v);
    return 0;
}

failed with:

g.cpp:13:8: error: cannot convert ‘int (*)[3]’ to ‘int**’ for argument ‘1’ to ‘void f(int**)’

But the following changes passed:

#include <stdlib.h>


void f(int ** v)
{
}

int main()
{
    int * v[2];
    f(v);
    return 0;
}

It seemed to me that the deeper dimensions of an array has to be solved upon compilation, and can somebody elaborate more about it?


Solution

  • C and C++ automatically coerce arrays to pointers. The error is caused due to the fact that this coercion happens only once (i.e. at only the first level). This means int [10] will get coerced to int *; but int [10][10] can at most get coerced to an int *[10].

    The reason has to do with memory layout. You see, a[i] translates to *(a + sizeof(T) * i) if a is of the type T * (assume adding to pointers directly adds without scaling); but if a is of the type T [N], a[i] translates to *(&a[0] + i). Thus, it follows that a value of type T [N] can be coerced into a value of type T * by taking the address of the first element -- the memory layouts are compatible in this case.

    However, a two dimensional array a (of type T [2] [4], say) will be stored differently than a double pointer (of type T **). In the first case, you have the four elements,T [0][0] to T [0][3] laid out in memory followed by T [1][0] to T [1][3] and so on, modulo alignment. In the second case, you just have a bunch of pointers (to T) laid out one after the other. In the first case, a[i][j] will get lowered into *(&a[0][0] + sizeof(T) * 4 * i + sizeof(T) * j) while in the second case it will get lowered into *(*(a + sizeof(T) * i) + sizeof(T) * j). The memory layouts are no longer compatible.