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()
{
i开发者_C百科nt 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);
}
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 malloc
ed memory to hold
the pointers to other chunks of malloc
ed 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 free
d 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 char
s or short
s or long
s or
whatever in your array instead of int
s, 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!
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.
You need to iterate again the array and do as many frees as mallocs for the pointed memory, and then free the array of pointers.
for (i = 0; i < m; i++) {
free (a[i]);
}
free (a);
Write your allocation operators in exactly reversed order, changing function names, and you'll be all right.
//Free the arrays
for (i = m-1; i >= 0; i--) {
free(a[i]);
}
free(a);
Of course, you don't have to deallocate in the very same reversed order. You just have to keep track on freeing same memory exactly once and not "forgetting" pointers to allocated memory (like it would have been if you free'd the a
first). But deallocating in the reverse order is a good role of thumb to address the latter.
As pointed by litb in the comments, if allocation/deallocation had side-effects (like new
/delete
operators in C++), sometimes the backward order of deallocation would be more important than in this particular example.
I would call malloc() and free() only once:
#include <stdlib.h>
#include <stdio.h>
int main(void){
int i, m = 5, n = 20;
int **a = malloc( m*(sizeof(int*) + n*sizeof(int)) );
//Initialize the arrays
for( a[0]=(int*)a+m, i=1; i<m; i++ ) a[i]=a[i-1]+n;
//...do something with arrays
//How do I free the **a ?
free(a);
return 0;
}
精彩评论