Search code examples
carraysmultidimensional-arraydynamic-allocationcontiguous

Attempting to dynamically allocate a multidimensional array in C results in a crash


For a multitude of reasons, I'd like to allocate multidimensional arrays in contiguous chunks of memory. I can do this by allocating them manually, eg:

t.versions=(char***)malloc(sizeof(char**)*4);
t.versions[0]=(char**)malloc(sizeof(char*)*t.size*4);
t.versions[0][0]=(char*)calloc(t.size*t.size*4,sizeof(char));
for (i=1; i<t.size*4; ++i) 
    t.versions[0][i]=t.versions[0][i-1]+t.size;
for (i=1; i<4; ++i) 
    t.versions[i]=t.versions[i-1]+t.size;

Among other benefits, this solution simplifies freeing the allocated memory:

void contiguous_array_free(void** ptr, int depth)
{
    int *ptr_d;
    ptr_d=(int*)*ptr;
    if (depth>1)
        contiguous_array_free((void**)ptr_d, depth-1);
    free(ptr);
}
//(elsewhere in the code)
contiguous_array_free((void**)(*tile).versions, 3);

Now, I've got a small problem with allocating those arrays - while the approach posted above does work, ideally I'd like to have a generic solution that allows me to allocate those arrays with a single function call.

However, my attempt to achieve that goal results in the program crashing every time the array contents are used.

//dimension points to a 1-dimensional array of integers
//specifying the size in each array dimension
void* contiguous_array_alloc(int* dimension, int depth, int size)
{
    int i;
    char** ptr;
    if (depth==1)
    {
        ptr=(char**)malloc(*dimension*size);
        return ptr;
    }
    ptr=(char**)malloc(*dimension*sizeof(char*));
    *(dimension+1)*=*dimension;
    ptr[0]=(char*)contiguous_array_alloc(dimension+1, depth-1, size);
    *(dimension+1)/=(*dimension);
    for (i=1; i<*dimension; ++i)
        ptr[i]=ptr[i-1]+(*(dimension+1)*size);
    return (void*)ptr;
}

//(later in the code) (
int dimension[3];
dimension[0]=4;
dimension[1]=t.size;
dimension[2]=t.size;
t.versions=(char***)contiguous_array_alloc(&dimension[0], 3, sizeof(char));

Adding some debug messages into the code seems to indicate the elements are allocated correctly:

Allocating [4][9][9] array of size 1 elements; malloc()ating 16 byte array for 4 pointers; Allocated pointer array to level 2 at 003E29E8;

Allocating [36][9] array of size 1 elements; malloc()ating 144 byte array for 36 pointers; Allocated pointer array to level 1 at 003E5728;

Allocating [324] array of size 1 elements;

324 byte data array at 003E57C0; Pointed data at 003E57C0; increasing every pointer by 9; Returning allocated array;

Pointed data at 003E5728; increasing every pointer by 9; Returning allocated array;

Allocated contiguous array at 003E29E8;

What is causing this behavior? I've checked the code several times and have no idea what I've done wrong.


Solution

  • I think there is something wrong for ptr[i]=ptr[i-1]+(*(dimension+1)*size); this kind of pointer operation usage does not make sense. I modified the code as below which passed the test for 4-dimension array.

    //dimension points to a 1-dimensional array of integers
    //specifying the size in each array dimension
    void* contiguous_array_alloc(int* dimension, int depth, int size) {
      int i;
      if (depth==2) {
        char ** ptr=(char **)malloc(*dimension * sizeof(void*));
        ptr[0]=(char *)malloc(*dimension * dimension[1] * size);
        for (i=1; i<*dimension; ++i) {
          ptr[i]=ptr[i-1]+(*(dimension+1) * size);
        }
        return (void*)ptr;
      } else {
        void ***ptr=(void***)malloc(*dimension * sizeof(void*));
        *(dimension+1)*=(*dimension);
        ptr[0]=contiguous_array_alloc(dimension+1, depth-1, size);
        *(dimension+1)/=(*dimension);
        for (i=1; i<*dimension; ++i) {
          ptr[i]=ptr[i-1]+(*(dimension+1));
        }
        return (void*)ptr;
      }
    }