4

I have this function to allocate memory to a matrix:

double **mmalloc(int r, int c){
    double **matrix = (double **)malloc((r)*sizeof(double*));
    for (int y = 0; y < r; y++){
        matrix[y] = (double *)malloc(c*sizeof(double));
    }

    for (int y = 0; y < r; y++){
        for(int x = 0; x < c; x++){
            matrix[y][x] = 0;
        }
    }
    return matrix;
}

How would I free all the memory of the returned matrix? I have this function to free the matrix... I can free the rows of the matrix but I cant free the columns.

Here's the freeing function:

// Free all memory allocated for A 
void mfree(int r, int c, double **A){
    for (int y = 0; y < r; y++){
        free(A[y]);
    }
}
Wesley
  • 89
  • 6
  • And as usual, [please don't cast the return value of `malloc`](http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc) ;) – Quentin Oct 26 '16 at 07:42

3 Answers3

3

You need to free all rows one by one, then the initially allocated column (that contains all rows)

void xfree(int r, int c, double **A){
    for (int y = 0; y < r; y++){
        free(A[y]);
    }
    free (A);
}

in this order.

double ** (Initial allocation)
  ↓
(double *)row0 → col0 col1 ...
(double *)row1 → col0 col1 ...
...

where each rowi is made of (double) columns.

In order to completely free a dynamically allocated array of arrays, keep these rules in mind

  • the number of frees has to equal the number of mallocs that was used to allocate the array and its arrays

  • consider that if something is freed it is not usable anymore, even if it may work by chance (the behavior that follows such action is said Undefined Behavior). For example, if you free(A) first, you shouldn't free(A[i]) since A - a memory space that contains a list of pointers - is not supposed to be allocated/usable anymore.

  • therefore free first the innermost elements ("contained", eg A[i]) then free the "containers" (eg A).

Déjà vu
  • 28,223
  • 6
  • 72
  • 100
2
void xfree(int r, int c, double **A){
    for (int y = 0; y < r; y++){
             free(A[y]);  
    }
    free(A)
}
Wasi Ahmad
  • 35,739
  • 32
  • 114
  • 161
0

I would 'cheat' and just allocate a contiguous block for your data, and then the second block to give you array access to your rows:

int main(){

    int r=3;
    int c=4;

    double* data = malloc(sizeof(double) * r * c);
    double** matrix = malloc(sizeof(double*) * r);

    int i;
    for (i=0;i<r;++i) { /* build the nice syntax accessor */
        matrix[i] = &data[i*c];
    }
    for (i=0;i<(r*c);++i) { /* you can fill/clear the whole matrix in one loop too */
        data[i] = i;
    }    

    // access data through matrix as a normal 2d array
    matrix[2][2] = 1.1;
    int x,y;
    for (x=0;x<r;++x) {
        for (y=0;y<c;++y) {
            printf("[%1.1f]", matrix[x][y]);
        }
        printf("\n");
    }

    // when done
    free(matrix);
    free(data);

    return 0;
}

Output:

[0.0][1.0][2.0][3.0]
[4.0][5.0][6.0][7.0]
[8.0][9.0][1.1][11.0]

I don't think it even matters what order you call the two frees (provided you do both and no access in between) since one array just points into the other - you maintain separate references to each.

You could even store data and matrix together in a struct or something and then have a function that takes that struct and frees both areas (or both areas and then the struct itself).

Note: this seemed to compile and work but I don't write C for a living, get a second opinion before using in production code in case I've missed something