I tried to assign two fixed-size arrays to an array of pointers to them, but the compiler warns me and I don\'t understand why.
int A[5][5];
int B[5][5];
int
A common misconception among C beginners is that they just assume pointers and arrays are equivalent. That's completely wrong.
Confusion comes to beginners when they see the code like
int a1[] = {1,2,3,4,5};
int *p1 = a1; // Beginners intuition: If 'p1' is a pointer and 'a1' can be assigned
// to it then arrays are pointers and pointers are arrays.
p1[1] = 0; // Oh! I was right
a1[3] = 0; // Bruce Wayne is the Batman! Yeah.
Now, it is verified by the beginners that arrays are pointers and pointers are arrays so they do such experiments:
int a2[][5] = {{0}};
int **p2 = a2;
And then a warning pops up about incompatible pointer assignment then they think: "Oh my God! Why has this array become Harvey Dent?".
Some even goes to one step ahead
int a3[][5][10] = {{{0}}};
int ***p3 = a3; // "?"
and then Riddler comes to their nightmare of array-pointer equivalence.
Always remember that arrays are not pointers and vice-versa. An array is a data type and a pointer is another data type (which is not array type). This has been addressed several years ago in the C-FAQ:
Saying that arrays and pointers are "equivalent" means neither that they are identical nor even interchangeable. What it means is that array and pointer arithmetic is defined such that a pointer can be conveniently used to access an array or to simulate an array. In other words, as Wayne Throop has put it, it's "pointer arithmetic and array indexing [that] are equivalent in C, pointers and arrays are different.")
Now always remember few important rules for array to avoid this kind of confusion:
sizeof
and &
operator.Now you have the rules, you can conclude that in
int a1[] = {1,2,3,4,5};
int *p1 = a1;
a1
is an array and in the declaration int *p1 = a1;
it converted to pointer to its first element. Its elements are of type int
then pointer to its first element would be of type int *
which is compatible to p1
.
In
int a2[][5] = {{0}};
int **p2 = a2;
a2
is an array and in int **p2 = a2;
it decays to pointer to its first element. Its elements are of type int[5]
(a 2D array is an array of 1D arrays), so a pointer to its first element would be of type int(*)[5]
(pointer to array) which is incompatible with type int **
. It should be
int (*p2)[5] = a2;
Similarly for
int a3[][5][10] = {{{0}}};
int ***p3 = a3;
elements of a3
is of type int [5][10]
and pointer to its first element would be of type int (*)[5][10]
, but p3
is of int ***
type, so to make them compatible, it should be
int (*p3)[5][10] = a3;
Now coming to your snippet
int A[5][5];
int B[5][5];
int*** C = {&A, &B};
&A
and &B
are of type int(*)[5][5]
. C
is of type int***
, it's not an array. Since you want to make C
to hold the address of both the arrays A
and B
, you need to declare C
as an array of two int(*)[5][5]
type elements. This should be done as
int (*C[2])[5][5] = {&A, &B};
However, if I dynamically allocate A and B it works just fine. Why is this?
In that case you must have declared A
and B
as int **
. In this case both are pointers, not arrays. C
is of type int ***
, so it can hold an address of int**
type data. Note that in this case the declaration int*** C = {&A, &B};
should be
int*** C = &A;
In case of int*** C = {&A, &B};
, the behavior of program would be either undefined or implementation defined.
C11: 5.1.1.3 (P1):
A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined
Read this post for further explanation.