Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C: Correctly freeing memory of a multi-dimensional array

Say you have the following ANSI C code that initializes a multi-dimensional array :

int main() {       int i, m = 5, n = 20;       int **a = malloc(m * sizeof(int *));        //Initialize the arrays       for (i = 0; i < m; i++) {            a[i]=malloc(n * sizeof(int));       }        //...do something with arrays        //How do I free the **a ?        return 0; } 

After using the **a, how do I correctly free it from memory ?


[Update] (Solution)

Thanks to Tim's (and the others) answer, I can now do such a function to free up memory from my multi-dimensional array :

void freeArray(int **a, int m) {     int i;     for (i = 0; i < m; ++i) {         free(a[i]);     }     free(a); } 
like image 921
Andreas Grech Avatar asked Nov 14 '09 10:11

Andreas Grech


People also ask

How are multi-dimensional arrays stored in memory?

Multidimensional Arrays in Memory. A 2D array is stored in the computer's memory one row following another. The address of the first byte of memory is considered as the memory location of the entire 2D array.

Can C language handle multidimensional arrays?

In C programming, you can create an array of arrays. These arrays are known as multidimensional arrays. For example, float x[3][4];

What is multi-dimensional array in C with example?

A multi-dimensional array is an array with more than one level or dimension. For example, a 2D array, or two-dimensional array, is an array of arrays, meaning it is a matrix of rows and columns (think of a table). A 3D array adds another dimension, turning it into an array of arrays of arrays.

How multidimensional arrays are declared in C?

Multidimensional arrays may be initialized by specifying bracketed values for each row. Following is an array with 3 rows and each row has 4 columns.


2 Answers

OK, there's a fair deal of confusion explaining exactly what order the necessary free() calls have to be in, so I'll try to clarify what people are trying to get at and why.

Starting with the basics, to free up memory which has been allocated using malloc(), you simply call free() with exactly the pointer which you were given by malloc(). So for this code:

int **a = malloc(m * sizeof(int *)); 

you need a matching:

free(a); 

and for this line:

a[i]=malloc(n * sizeof(int)); 

you need a matching:

free(a[i]); 

inside a similar loop.

Where this gets complicated is the order in which this needs to happen. If you call malloc() several times to get several different chunks of memory, in general it doesn't matter what order you call free() when you have done with them. However, the order is important here for a very specific reason: you are using one chunk of malloced memory to hold the pointers to other chunks of malloced memory. Because you must not attempt to read or write memory once you have handed it back with free(), this means that you are going to have to free the chunks with their pointers stored in a[i] before you free the a chunk itself. The individual chunks with pointers stored in a[i] are not dependent on each other, and so can be freed in whichever order you like.

So, putting this all together, we get this:

for (i = 0; i < m; i++) {    free(a[i]); } free(a); 

One last tip: when calling malloc(), consider changing these:

int **a = malloc(m * sizeof(int *));  a[i]=malloc(n * sizeof(int)); 

to:

int **a = malloc(m * sizeof(*a));  a[i]=malloc(n * sizeof(*(a[i]))); 

What's this doing? The compiler knows that a is an int **, so it can determine that sizeof(*a) is the same as sizeof(int *). However, if later on you change your mind and want chars or shorts or longs or whatever in your array instead of ints, or you adapt this code for later use in something else, you will have to change just the one remaining reference to int in the first quoted line above, and everything else will automatically fall into place for you. This removes the likelihood of unnoticed errors in the future.

Good luck!

like image 98
Tim Avatar answered Oct 20 '22 16:10

Tim


Undo exactly what you allocated:

  for (i = 0; i < m; i++) {        free(a[i]);   }   free(a); 

Note that you must do this in the reverse order from which you originally allocated the memory. If you did free(a) first, then a[i] would be accessing memory after it had been freed, which is undefined behaviour.

like image 43
Greg Hewgill Avatar answered Oct 20 '22 15:10

Greg Hewgill