What you want can't work directly. For indexing a multi-dimensional array, all but the very first dimension need to be part of the type and here's why:
The indexing operator operates on pointers by first adding an index to the pointer and then dereferencing it. The identifier of an array evaluates to a pointer to its first element (except when e.g. used with sizeof
, _Alignof
and &
), so indexing on arrays works as you would expect.
It's very simple in the case of a single-dimension array. With
int a[42];
a
evaluates to a pointer of type int *
and indexing works the following way: a[18] => *(a + 18)
.
Now in a 2-dimensional array, all the elements are stored contiguously ("row" after "row" if you want to understand it as a matrix), and what's making the indexing "magic" work is the types involved. Take for example:
int a[16][42];
Here, the elements of a
have the type int ()[42]
(42-element array of int). According to the rules above, evaluating an expression of this type in most contexts again yields an int *
pointer. But what about a
itself? Well, it's an array of int ()[42]
so a
will evaluate to a pointer to 42-element array of int: int (*)[42]
. Then let's have a look at what the indexing operator does:
a[3][18] => *(*(a + 3) + 18)
With a
evaluating to the address of a
with type int (*)[42]
, this inner addition of 3
can properly add 42 * sizeof(int)
. This would be impossible if the second dimension wasn't known in the type.
I guess it's simple to deduce the example for the n-dimensional case.
In your case, you have two possibilities to achieve something similar to what you want.
Use a dynamically allocated flat array with size 6*N*N
. You can calculate the indices yourself if you save N
somewhere.
Somewhat less efficient, but yielding better readable code, you could use an array of pointers to arrays of pointers to int (multiple indirection). You could e.g. do
int ***a = malloc(6 * sizeof *int);
for (size_t i = 0; i < 6; ++i)
{
a[i] = malloc(N * sizeof *(a[i]));
for (size_t j = 0; j < N ++j)
{
a[i][j] = malloc(N* sizeof *(a[i][j]));
}
}
// add error checking to malloc calls!
Then your accesses will look just like those to a normal 3d array, but it's stored internally as many arrays with pointers to the other arrays instead of in a big contiguous block.
I don't think it's worth using this many indirections, just to avoid writing e.g. a[2*N*N+5*N+4]
to access the element at 2,5,4
, so my recommendation would be the first method.