I\'m translating some MATLAB code into C and the script I\'m converting makes heavy use of 3D arrays with 10*100*300 complex entries. The size of the array also depends on t
About the segfault, I am pretty sure someone else has pointed this out but just in case, there is a extra '*' in the first line of the first for loop
for (i = 0; i < 3; i++) {
*array[i] = malloc(3*sizeof(int*));
// ^ we dont want to deference array twice
for (j = 0; j < 3; j++) {
array[i][j] = malloc(3*sizeof(int));
}
}
try the following:
for (i = 0; i < 3; i++) {
array[i] = malloc(3*sizeof(int*));
for (j = 0; j < 3; j++) {
array[i][j] = malloc(3*sizeof(int));
}
}
add #include "stdlib.h" and remove the * from *array[i] and it will run when compiled in gcc 4.4.1 on Ubuntu
also if you add print statements you can find your bugs quicker
#include <stdio.h>
#include <stdlib.h>
int main () {
int ***array = malloc(3*sizeof(int**));
int i, j;
printf("%s\n","OK");
for (i = 0; i < 3; i++) {
printf("i = %i \n",i);
array[i] = malloc(3*sizeof(int*));
for (j = 0; j < 3; j++) {
printf("i,j = %i,%i \n",i,j);
array[i][j] = malloc(3*sizeof(int));
}
}
array[1][2][1] = 10;
return 0;
}
As others have said, it is probably better to allocate one contiguous chunk of memory, and then figure out the indexing yourself. You can write a function to do so if you want. But since you seem to be interested in knowing how to deal with the multiple malloc()
case, here is an example:
First, I define a function free_data()
, which frees an int ***
with xlen
and ylen
as the first two dimension sizes. We don't need a zlen
parameter just like free()
doesn't take the length of the pointer being freed.
void free_data(int ***data, size_t xlen, size_t ylen)
{
size_t i, j;
for (i=0; i < xlen; ++i) {
if (data[i] != NULL) {
for (j=0; j < ylen; ++j)
free(data[i][j]);
free(data[i]);
}
}
free(data);
}
The function loops over the pointer data
, finds out the i
th int **
pointer data[i]
. Then, for a given int **
pointer, it loops over it, finding out the j
th int *
in data[i][j]
, and frees it. It also needs to free data[i]
once it has freed all data[i][j]
, and finally, it needs to free data
itself.
Now to the allocation function. The function is a bit complicated by error checking. In particular, since there are 1 + xlen + xlen*ylen
malloc
calls, we have to be able to handle a failure in any of those calls, and free all the memory we allocated so far. To make things easier, we rely on the fact that free(NULL)
is no-op, so we set all the pointers at a given level equal to NULL
before we try to allocate them, so that if an error happens, we can free all of the pointers.
Other than that, the function is simple enough. We first allocate space for xlen
int **
values, then for each of those xlen
pointers, we allocate space for ylen
int *
values, and then for each of those xlen*ylen
pointers, we allocate space for zlen
int
values, giving us a total space for xlen*ylen*zlen
int
values:
int ***alloc_data(size_t xlen, size_t ylen, size_t zlen)
{
int ***p;
size_t i, j;
if ((p = malloc(xlen * sizeof *p)) == NULL) {
perror("malloc 1");
return NULL;
}
for (i=0; i < xlen; ++i)
p[i] = NULL;
for (i=0; i < xlen; ++i)
if ((p[i] = malloc(ylen * sizeof *p[i])) == NULL) {
perror("malloc 2");
free_data(p, xlen, ylen);
return NULL;
}
for (i=0; i < xlen; ++i)
for (j=0; j < ylen; ++j)
p[i][j] = NULL;
for (i=0; i < xlen; ++i)
for (j=0; j < ylen; ++j)
if ((p[i][j] = malloc(zlen * sizeof *p[i][j])) == NULL) {
perror("malloc 3");
free_data(p, xlen, ylen);
return NULL;
}
return p;
}
Note that I have simplified malloc
calls quite a bit: in general, you shouldn't cast the return value of malloc
, and specify the object you're allocating for as the operand to sizeof
operator instead of its type. That makes malloc
calls simpler to write and less error-prone. You need to include stdlib.h
for malloc
.
Here is a test program using the above two functions:
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <time.h>
int main(void)
{
int ***data;
size_t xlen = 10;
size_t ylen = 100;
size_t zlen = 300;
size_t i, j, k;
srand((unsigned int)time(NULL));
if ((data = alloc_data(xlen, ylen, zlen)) == NULL)
return EXIT_FAILURE;
for (i=0; i < xlen; ++i)
for (j=0; j < ylen; ++j)
for (k=0; k < zlen; ++k)
data[i][j][k] = rand();
printf("%d\n", data[1][2][1]);
free_data(data, xlen, ylen);
return EXIT_SUCCESS;
}
By all means use this approach if you find it easier to use it. In general, this will be slower than using a contiguous chunk of memory, but if you find that the speed is OK with the above scheme, and if it makes your life easier, you can keep using it. Even if you don't use it, it is nice to know how to make such a scheme work.
Below the Code for 3d memory allocations:
int row3d = 4;
int column3d = 4;
int height3d =4;
int val3d =10;
int ***arr3d = (int***)malloc (row3d*sizeof(int**));
for (int i =0 ; i<column3d;i++)
{
arr3d[i] = (int**)malloc (column3d*sizeof(int*));
for (int j = 0;j<height3d;j++)
{
arr3d[i][j] = (int*)malloc (height3d*sizeof(int));
for (int z =0;z<height3d;z++,val3d++)
{
arr3d[i][j][z] = val3d;
}
}
}
// De allocation.
for (int i=0;i<row3d;i++)
{
for(int j=0;j<column3d;j++)
{
free(arr3d[i][j]);
}
}
free(arr3d);
arr3d = 0;
Hope this will help you!!!!
While allocating memory for 2D array inside 3D array, assign the allocated memory to array[i] and not *array[i] and this will work without seg fault.
Here is your program
int main ()
{
int ***array = malloc(3*sizeof(int**));
int i, j;
for (i = 0; i < 3; i++) {
array[i] = malloc(3*sizeof(int*));
for (j = 0; j < 3; j++) {
array[i][j] = malloc(3*sizeof(int));
}
}
array[1][2][1] = 10;
return 0;
}
There is no way in C89 to do what you desire, because an array type in C can only be specified with compile time known values. So in order to avoid the mad dynamic allocation, you will have to stick to the one dimensional way. You may use a function to ease this process
int index(int x, int y, int z) {
return x + (y*xSize) + (z*ySize*xSize);
}
int value = array[index(a, b, c)];
In C99 you can use an ordinary array syntax even if the dimensions are runtime values:
int (*array)[X][Y][Z] = (int(*)[X][Y][Z])malloc(sizeof *p);
// fill...
int value = (*array)[a][b][c];
However, it only works with local non-static arrays.