0

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?

Hailiang Zhang
  • 17,604
  • 23
  • 71
  • 117
  • 3
    The former is not a pointer to a pointer, it's a 2D array (which will decay to a pointer to an array). Arrays are not pointers. – netcoder Jan 10 '13 at 18:39
  • possible duplicate of [Passing multidimensional arrays as function arguments in C](http://stackoverflow.com/questions/4051/passing-multidimensional-arrays-as-function-arguments-in-c), or [Why can't I convert a two-dimensional array to a two-dimensional pointer in C?](http://stackoverflow.com/questions/8264392/why-cant-i-convert-a-two-dimensional-array-to-a-two-dimensional-pointer-in-c), or many others. – netcoder Jan 10 '13 at 18:43
  • 1
    [My compiler complained when I passed a two-dimensional array to a function expecting a pointer to a pointer.](http://c-faq.com/aryptr/pass2dary.html) And why this C tagged question has a C++ example? – effeffe Jan 10 '13 at 18:47
  • @effeffe because, correct me if I'm wrong, the OP does not have a clue what the hell he is doing. Is it safe to retag the question as C++? – Andreas Grapentin Jan 10 '13 at 19:48
  • @Andreas Grapentin Source code editted to remove the C++ features. Please use the right words! – Hailiang Zhang Jan 10 '13 at 23:00

2 Answers2

2

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.

sanjoyd
  • 3,260
  • 2
  • 16
  • 22
  • Great answer! Explanations on the memory layout is exactly what I am looking for! Just make sure it's a typo. Should a[i][j] be lowered to *(*(a + sizeof(*T) * i) + sizeof(T) * j) instead of *(*(a + sizeof(T) * i) + sizeof(T) * j)? – Hailiang Zhang Jan 10 '13 at 22:43
0

A pointer to an int is something different than a pointer to an array.

When doing v++, the compiler must be informed, if to increment the address by sizeof(int) or by array_length*sizeof(int)

nkdm
  • 1,220
  • 1
  • 11
  • 26