To be honest, generally the best way for allocating an N-dimensional array would be to do it in one huge hunk: double *make_matrix(size_t N, size_t *dimSizes, size_t sizeOfElement) { size_t total = dimSizes[0]; for(size_t i = 1; i < N; ++i) { total *= dimSizes[i]; } return (double*)malloc(total * sizeOfElement); } And then manage your own strides using dimSizes. So for access in a 3D matrix of size 4x5x6, with 1, 2, 3: size_t dimSizes[3] = {4, 5, 6}; double *mat = make_matrix(3, dimSizes, sizeof(double)); double element = mat[1*5*6 + 2*6 + 3]; Brian On Mon, Dec 7, 2009 at 12:24 AM, Cedric Roux <cedric.roux@xxxxxxxxxx> wrote: > Thanks for your replies John and Axel. > Problem is I am still not convinced. > I thought about it this week-end, and here comes > my reflexions. > > So there is make_matrix(). > I will use it as: > > double ***x = make_matrix(3, dim, sizeof(double)); > > to get a matrix of double with 3 dimensions. > And: > > struct dumb ****y = make_matrix(4, dim2, sizeof(struct dumb)); > > to get a matrix of "struct dumb" with 4 dimensions. > > My real question would more be: > does an access like "x[1][2][3]" gives me what I expect > on every platform gcc works on? what about the c99 standard > on that? > > If I understand correctly c99, it says we can go from/to > a void* and get the same pointing stuff. And, if alignment > is respected it also works to convert to another type, > when we cast back we get the same address > (6.3.2.3.7 in n1336.pdf). > (Correct me if I'm wrong on this one.) > > Now, let's stay with double ***. > > In make_matrix we setup the array of pointers with void* > pointers, not double* and double**, which is what we > really use later on. > > Let's become a bit more concrete. Let's say a pointer > is on 8 bits, so XXXXXXXX in binary. > > What if a void* is stored in memory as XXXXXXXX > but a double, which would point to an 8 bytes > number (let's say it's a IEEE 754 double) would > normally be stored as XXXXX000 (let's suppose > the hardware wants alignment) so that the > engineers of this CPU said: "uh, but we waste > 3 bits, let's store double* as YYYXXXXX, so > we get 8 times more numbers to point to!" > > And they invent ldd reg,add and std add,reg > to load and store using the "extended address" > or whatever they would call that. > > See the problem? Now a void* is no more like a > double*. And accessing x[1][2][3] would not > work since x is double*** but the memory it > points to has been populated with void*, > so the "ldd reg,add" will miserably fail > somewhere in the indirections. > > Well, that's how I understand c99. Am I > correct? In practice, are there cases > such as the hypothetical one I presented? > Can I trust my code (even if not c99 correct) > to work on the hardware I will encounter in > practice? Are there architectures out there > where it will fail? > > Thanks, > Cédric. >