1

I am puzzled by the memory allocation and accesses to a matrix of pointers in an application I am working in.

There is a matrix defined as:

typedef double (*foo)[n/m][m][m];

Which I understand to be a three-dimensional matrix storing pointers to doubles. The memory allocation for all dimensions is done automatically.

Nonetheless, the following appears:

foo bar = (foo) malloc(sizeof(double) * n * n);

What exactly is this cast doing?. Furthermore, why do we need to allocate memory for these doubles?. I would think the matrix only contains pointers, which would later be initialized with the memory addresses of doubles declared separately.

Finally, I am, also confused by the way this matrix is accessed during its initialization:

bar[i/m][j/m][i%m][j%m] = value;

Where i and j are smaller than N. Mainly, I would like to know what the fourth index is adressing.

Thank you so much in advance for your help!

Juan González
  • 177
  • 1
  • 3
  • 10
  • 3
    The cast isn't doing anything. C doesn't require a cast when converting `void*` to another pointer type. – Barmar May 19 '20 at 22:19
  • does this answer your question: https://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc . People cast malloc for no logical reason, they just saw someone else do it. The cast has no effect other than to possibly cause suppression of important warnings – M.M May 19 '20 at 22:22
  • 1
    @JG55 This typedef double (*foo)[n/m][m][m]; is a declaration of an alias for the type pointer to three dimensional array.. It is not "a three-dimensional matrix storing pointers to doubles" – Vlad from Moscow May 19 '20 at 22:26
  • @M.M Thank you, that is interesting. I am still confused by the allocation itself, though. – Juan González May 19 '20 at 22:28
  • 1
    it looks like the array dimensions are [n/m][n/m][m][m] , when you malloc an array of arrays via pointer to the first element then the first dimension does not form part of the type . The size could have been written as `sizeof(int [n/m][n/m][m][m])` but the author optimized that to `n*n` – M.M May 19 '20 at 22:28
  • 1
    [see here](https://stackoverflow.com/questions/3584705/defining-a-2d-array-with-malloc-and-modifying-it) for example in 2 and 3-D, and then imagine extra 2 dims – M.M May 19 '20 at 22:33
  • @M.M That example was really helpful. Just to make sure I understand this correctly, foo is defined as a pointer to an [n/m][m][m] array of doubles. Bar is allocated, n*n doubles. This is the size of n/m instances of foo, which makes bar an array of n/m pointers to [n/m][m][m] arrays of doubles. Is this correct? – Juan González May 19 '20 at 22:55
  • 1
    This `double (*foo)[n/m][m][m]` creates 1 single pointer `foo` that will be used to point 3 dimensional arrays containing values of type `double`, where the size of each of the 3 dimensions are `n/m`, `m` and `m` respectively, for a total of `(n/m)*m*m = n*m` `double` values in each 3 dimensional array. – isrnick May 19 '20 at 23:37
  • 1
    Note that you can use pointer's arithmetic over foo, so if `foo` points to the one 3 dimensional array, then `foo+1` will point to the next 3 dimensional array. So, in pointer notation you would do `(*(foo+1))[0][0][0]` to access the first `double` value of the second 3 dimensional array, and you can rewrite this using array notation as `foo[1][0][0][0]` to do the same thing. So now you can see that by iterating over `foo` you are iterating over the 4th dimension of a 4 dimensional array. – isrnick May 19 '20 at 23:43
  • 1
    From the code we see that it was allocated `n*n` `double` values for this 4 dimensional array, so we don't know the size of the forth dimesion, and we could say that the dimensions of the array are something like `[x][n/m][m][m]` where `x` is the unknown size, but we know that this 4 dimensional array will have `n*n` elements, so to find `x` we need to solve `x*(n/m)*m*m = n*n`, therefore `x = n\m`, and the dimensions are `[n/m][n/m][m][m]`. – isrnick May 19 '20 at 23:55
  • I see, thats what I understood from the other comments, but a way better explanation than mine. Would you like to make these comments into an answer? The previous comments were really useful as well. I feel that this explanation is easier to grasp, though. – Juan González May 20 '20 at 00:10
  • Done as requested. `:-)` – isrnick May 20 '20 at 00:39

1 Answers1

3

This double (*foo)[n/m][m][m] creates 1 single pointer foo that will be used to point to 3 dimensional arrays containing values of type double, where the size of each of the 3 dimensions are n/m, m and m respectively, for a total of (n/m)*m*m = n*m double values in each 3 dimensional array.

Note that you can use pointer's arithmetic over foo, so if foo points to one 3 dimensional array, then foo+1 will point to the next 3 dimensional array.

In pointer notation you would do (*(foo+1))[0][0][0] to access the first double value of the second 3 dimensional array, and you can rewrite this using array notation as foo[1][0][0][0] to do the same thing. So now you can see that by iterating over foo you are iterating over the 4th dimension of a 4 dimensional array.

From the code we see that it allocated n*n double values for this 4 dimensional array. So, as we don't know the size of the forth dimension, we could say that the dimensions of the array are something like [x][n/m][m][m] where x is the unknown size. But we do know that this 4 dimensional array will have n*n elements, so to find x we need to solve x*(n/m)*m*m = n*n, therefore x = n/m, and the dimensions are [n/m][n/m][m][m].

isrnick
  • 621
  • 5
  • 12