Something like that is fairly simple to check (a):
#include <stdio.h>
int main (void) {
int a[2][3][4][5];
// Ignore incorrect format specifiers for now.
printf ("%d\n", sizeof(int));
printf ("%d\n", &(a[0][0][0][0]));
printf ("%d\n", &(a[1][1][1][1]));
printf ("%d\n", (int)&(a[1][1][1][1])
- (int)&(a[0][0][0][0])
+ 1000);
return 0;
}
and the output of that is:
4
2665056
2665400
1344
Note the conversions of the pointers to int
values in that final printf
. Without this, the 1000
would be scaled as an int *
, giving the wrong value.
So, yes, bottom line, your reasoning is correct.
(a) That's not always the case since some aspects of the C language can differ across implementations (implementation-specified behaviour) or in any way they want (undefined behaviour).
Happily, layout of arrays is specified specifically by the standard, in C11 6.5.2.1 Array subscripting
:
2/ A postfix expression followed by an expression in square brackets []
is a subscripted designation of an element of an array object. The definition of the subscript operator []
is that E1[E2]
is identical to (*((E1)+(E2)))
. Because of the conversion rules that apply to the binary +
operator, if E1
is an array object (equivalently, a pointer to the initial element of an array object) and E2
is an integer, E1[E2]
designates the E2-th
element of E1
(counting from zero).
3/ Successive subscript operators designate an element of a multidimensional array object. If E
is an n-dimensional array (n >= 2) with dimensions i * j * ... * k
, then E
(used as other than an lvalue) is converted to a pointer to an (n − 1)-dimensional array with dimensions j * ... * k
. If the unary *
operator is applied to this pointer explicitly, or implicitly as a result of subscripting, the result is the referenced (n − 1)-dimensional array, which itself is converted into a pointer if used as other than an lvalue. It follows from this that arrays are stored in row-major order (last subscript varies fastest).