Reputation: 309
Why aren't these function prototypes equivalent?
void print_matrix(char *name, int SX, int SY, int m[SX][SY])
void print_matrix(char *name, int SX, int SY, int **m)
Upvotes: 1
Views: 190
Reputation: 477030
Even though the two function arguments can be consumed in the same way, namely via m[i][j]
, they're quite different:
int m[M][N]
is an array of M
arrays of N
ints.
int **m
is a pointer to a pointer to an int.
You cannot pass arrays as function arguments, so an "array of K
elements of type T
" decays to a "pointer-to-T
", pointing to the first element of the array. Thus it is permissible and equivalent to write the first form as int m[][N]
in a function argument, since the value M
is lost. However, the value N
is not lost; it is part of the type!
So the following are admissible/erroneous for the first form:
void f(int arr[M][N]);
int a[M][N];
int b[2*M][N];
int c[M][N + 1];
f(a); // OK
f(b); // OK; slowest extent is forgotten in the decay
//f(c); // Error! 'c' is not an array of {array of N ints}.
For the second form, the meaning is rather different:
void g(int **p);
int a;
int * pa = &a;
g(&pa); // fine, pointer to 'pa'
int arr[M][N];
// g(arr); // Error, makes no sense
The expression arr
designates the pointer to the first element of an array of arrays of N
integers, i.e. its type is int (*)[N]
. Dereferencing it gives an array of N
integers, and not a pointer to an integer.
There is no way to convert the expression arr
into a pointer to a pointer: If you said,
int ** fool = (int**)arr;
then *fool
would point to the first element of the first array (arr[0]
), and not to an int
pointer. So you cannot dereference the value further, because the value is not a pointer.
The only correct way to pass a two-dimensional array as a double pointer is to construct an intermediate helper array:
int * helper[M]; // array of pointers
for (size_t i = 0; i != M; ++i)
{
helper[i] = arr[i]; // implicit decay
}
g(helper); // or "g(&helper[0])"
Upvotes: 6