I had in mind a solution similar to what @tstanisl posted. I've never done this, so I had some doubts about how to make it work, and so I developed a simple program to show it:
$ cat ap.c
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
#define ARRAY_SSIZE(a) ((ptrdiff_t) ARRAY_SIZE(a))
int main(void)
{
int (*ap)[2][3][5];
int l = 0;
ap = malloc(sizeof(*ap));
printf("%zu\n", sizeof(*ap));
for (ptrdiff_t i = 0; i < ARRAY_SSIZE(*ap); ++i) {
for (ptrdiff_t j = 0; j < ARRAY_SSIZE((*ap)[0]); ++j) {
for (ptrdiff_t k = 0; k < ARRAY_SSIZE((*ap)[0][0]); ++k) {
(*ap)[i][j][k] = l++;
}
}
}
for (ptrdiff_t i = 0; i < ARRAY_SSIZE(*ap); ++i) {
for (ptrdiff_t j = 0; j < ARRAY_SSIZE((*ap)[0]); ++j) {
for (ptrdiff_t k = 0; k < ARRAY_SSIZE((*ap)[0][0]); ++k)
printf("%3i", (*ap)[i][j][k]);
putchar('\n');
}
putchar('\n');
}
}
$ ./a.out
120
0 1 2 3 4
5 6 7 8 9
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24
25 26 27 28 29
I hope it's useful :-)
I did some further testing to check that there's no undefined behavior, and also to check that the addresses that I'm accessing are contiguous, but I removed them here to simplify the code.
Edit:
My solution above is slightly different from @tstanisl 's. The below is what he suggested. Use the one you prefer. Both are nice.
This one is more similar to what you get in functions where an array decays to a pointer to its first element.
$ cat ap.c
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#define ARRAY_SIZE(a) (sizeof((a)) / sizeof((a)[0]))
#define ARRAY_SSIZE(a) ((ptrdiff_t) ARRAY_SIZE(a))
int main(void)
{
int (*ap/*[2]*/)[3][5];
int l = 0;
ap = malloc(sizeof(*ap) * 2);
printf("%zu\n", sizeof(*ap) * 2);
for (ptrdiff_t i = 0; i < 2; ++i) {
for (ptrdiff_t j = 0; j < ARRAY_SSIZE(ap[0]); ++j) {
for (ptrdiff_t k = 0; k < ARRAY_SSIZE(ap[0][0]); ++k) {
ap[i][j][k] = l++;
}
}
}
for (ptrdiff_t i = 0; i < 2; ++i) {
for (ptrdiff_t j = 0; j < ARRAY_SSIZE(ap[0]); ++j) {
for (ptrdiff_t k = 0; k < ARRAY_SSIZE(ap[0][0]); ++k)
printf("%3i", ap[i][j][k]);
putchar('\n');
}
putchar('\n');
}
}
$ ./a.out
120
0 1 2 3 4
5 6 7 8 9
10 11 12 13 14
15 16 17 18 19
20 21 22 23 24
25 26 27 28 29