This C approach only really works as long as the dimensions are known at
compile time and the arrays are small (larger arrays won't fit on stack).
In C++, suggesting a custom class containing a plain std::vector for
data storage and separate dimension info, providing some kind of 3D
interface on top of that.
Details depend on whether you prefer simple nice interfaces over speed,
what are your typical dimensions, and what are your typical operations.
In case you are interested in nice interfaces, one can provide nice
operator[] overloads with proxies, so that you can access elements of
your array via nice arr[x][y][z], or technically simpler arr.Elem(x, y, z).
In case you are interested in performance, one needs to avoid arithmetic
or multiple indirections when accessing single elements, and one needs
to take care about memory locality. This in general means that the 3D
abstraction becomes leaky; the algorithm working on the data would need
to take out pointers to the whole linear array, or to the most tightly
packed linear stretches, and iterate over them by itself. A single pixel
access function like arr[x][y][z] or arr.Elem(x, y, z) would be pretty
useless.
No doubt there are already a myriad of multidimensional array libraries
out there, but as the right solution depends on your needs, data, and
usage, finding a suitable library might be more complicated than writing
your own class suited to your needs.