Search code examples
carraysmalloccalloc

Correct interpretation of dynamic 2D array allocation in C


I have problem to correctly interpret two different ways of dynamically allocation 2D arrays in C.

This first method reads (for readability, I left out the if(arr==NULL) checks):

double** matrix_d( long int Nrows, long int Ncols ) {
    long int  ii;
    double**  arr;
    // allocate pointer to rows 
    arr = calloc( Nrows , (sizeof *arr));        
    for( ii=0 ; ii < Nrows; ii++) {
        // allocate pointer to each column (?)
        arr[ii] = calloc( Ncols , (sizeof **arr) );
    }
    return arr;
}

The second method reads (again, omitting the check of the return-value of calloc):

double** matrix_d2( long int Nrows, long int Ncols ) {
    long int  ii;
    double**  arr;
    // allocate pointers to rows
    arr = calloc( Nrows , (sizeof *arr) );
    // allocate rows (?)
    arr[0] = calloc( Nrows*Ncols, (sizeof arr) );
    // set pointers to rows (?)
    for( ii=0 ; ii < Nrows; ii++)
        arr[ii] = (*arr + Ncols*ii);
    return arr;

The comment-lines reveal probably my lack of understanding the memory allocation properly... especially the second method is somehow confusing to me (but seems to be "better" in that sense that it requires only 2 calloc/malloc calls).

Could one of you probably point me to the correct interpretation? That would be greatly appreciated! }

EDIT: there was a typo in both methods' first calloc call


Solution

  • Assuming the matix_d is clear.

    The second function creates two areas of memory. One to store pointers to the columns and one to hold the data itself.

    Every "position" in the of the first level of the array a position in the second area of memory is stored.

    The method of storing and collecting the second area of memory is a little confusing. First arr[0] is assigned and is retrieved with *arr. Which is the same.

    Also, when adding 1 to a pointer will increase the pointer value with the size of the data the pointer is pointing to. So ((double*)0) + 1 is the same as ((double*)sizeof(double)).

    To my opinion it is better to use a local pointer to the second area of memory and use that one in the for loop.

    Secondly, the sizeof is wrong. You want to allocate (cols * rows) of doubles. Use sizeof(**arr) or just sizeof(double).

    double** matrix_d2( long int Nrows, long int Ncols ) {
        long int  ii;
        double* data;
        double**  arr;
        // allocate pointers to rows
        arr = calloc( Nrows , (sizeof arr) );
        // allocate data rows * cols
        data = calloc( Nrows*Ncols, (sizeof **arr) );
        // set pointers to rows
        for( ii=0 ; ii < Nrows; ii++)
            arr[ii] = (data + (Ncols*ii));
        return arr;
    

    Does this help you with the interpretation of the code?