The way to read a multidimensional array declaration like
int arr[N][M];
is as an N-element array of M-element arrays of int
. Each arr[i]
has type int [M]
.
We can get there using substitution. Let's start with a simple object declaration:
T a;
a
is an instance of something which we call T
. Now replace T
with the array type R [N]
:
R a[N];
Important thing to note - since the []
operator is postfix in both expressions and declarations, when we substitute T
with R [N]
the [N]
goes to the rightmost side of the declarator a
, giving us R a[N]
; the importance of this will be clear on the next round of substitution.
So now a
is an N-element array of something, and that something is type R
. Now we replace R
with another array type, int [M]
:
int a[N][M];
Again, since the []
operator is postfix, we need to add it to the rightmost side of the declarator a[N]
when doing the substitution, giving us a[N][M]
. a
is still an N-element array of something, it's just now that something is "M-element array of int
". Hence, a
is an N-element array of M-element arrays of int
.
But even this is not entirely correct because int a[][3] = {1,2,3,4,5,6,7}; is valid even though the RHS contains a number of elements not divisible by 3.
That's covered here:
6.7.9 Initialization
...
21 If there are fewer initializers in a brace-enclosed list than there are elements or members
of an aggregate, or fewer characters in a string literal used to initialize an array of known
size than there are elements in the array, the remainder of the aggregate shall be
initialized implicitly the same as objects that have static storage duration.
C 2011 Online Draft
So that initializer is interpreted as:
int a[][3] = {{1,2,3},{4,5,6},{7,0,0}};