The way an array is dereferenced is like so:
float* data = float [8];
data[5] = *(data + 5);
float* data = float [10][3];
data[7][1] = *(data + ((10 * 7) + 1));
float* data = float [2][4][6];
data[2][3][5] = *(data + ((((2 * (2 * 4)) + (3 * 4)) + 5);
etc
Multi-dimensional arrays are implemented as just arrays and the compiler specifies the additional math needed for the dimensions after the first. This is different from having an array of pointers to floats, which is what float** points to.
For additional clarification, in the case of float** p = new float [n][5];
, the memory allocated is SIZEOF(float) * n * 5
bytes and p
is set to a pointer to that memory. The compiler does not allow you to assign to a float**
for good reason, not because it is forcing you to keep with standards or conventions or something. If you were to dereference it manually as you would a valid one-dimensional float**
to a one-dimensional array of floats, in a way such as (for example, second element in third row) *(*(p + (n * 2)) + 1)
, then the float
would be read as a pointer type, probably UINT32
or UINT64
on most modern systems, and so in either case the float
would be dereferenced, almost certainly on an invalid location, causing a memory access violation, or otherwise to some valid location that has other data and would still certainly not be what you intended to get. And on top of that, in the case of 64-bit systems, you could get a memory access violation already on the first stage if the array were allocated as float** p = new float [1][1];
, because the 64-bit pointer expected would be larger than the float
allocated, as they are typically 32 bits in size.