C: Liberar correctamente la memoria de una matriz multidimensional
Supongamos que tiene el siguiente código ANSI C que inicializa una matriz multidimensional:
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;
}
Después de usar el **a
, ¿cómo puedo liberarlo correctamente de la memoria ?
[Actualización] (Solución)
Gracias a la respuesta de Tim (y los demás) , ahora puedo hacer tal función para liberar memoria de mi matriz multidimensional:
void freeArray(int **a, int m) {
int i;
for (i = 0; i < m; ++i) {
free(a[i]);
}
free(a);
}
5 answers
OK, hay un trato justo de confusión explicando exactamente qué orden el
free()
llamadas necesarias tienen que estar en, así que voy a tratar de aclarar lo que
la gente está tratando de llegar y por qué.
Comenzando con lo básico, para liberar memoria que ha sido asignada
usando malloc()
, simplemente llama a free()
con exactamente el puntero
que te fue dado por malloc()
. Así que para este código:
int **a = malloc(m * sizeof(int *));
Necesitas una coincidencia:
free(a);
Y para esta línea:
a[i]=malloc(n * sizeof(int));
Usted necesita un coincidencia:
free(a[i]);
Dentro de un bucle similar.
Donde esto se complica es el orden en el que esto tiene que suceder. Si
usted llama malloc()
varias veces para obtener varios trozos diferentes de
memoria, en general no importa qué orden llame free()
cuando
has terminado con ellos. Sin embargo, el orden es importante aquí para un muy
razón específica: está utilizando un trozo de malloc
memoria ed para mantener
los punteros a otros trozos de memoria ed malloc
. Porque debe
no intente leer o escribir memoria una vez que la haya devuelto con
free()
, esto significa que vas a tener que liberar los trozos con
sus punteros almacenados en a[i]
antes de se libera el a
trozo en sí.
Los trozos individuales con punteros almacenados en a[i]
no dependen de cada uno
otro, y así puede ser free
d en el orden que desee.
Así que, juntando todo esto, obtenemos esto: {[31]]}
for (i = 0; i < m; i++) {
free(a[i]);
}
free(a);
Un último consejo: al llamar malloc()
, considere cambiar estos:
int **a = malloc(m * sizeof(int *));
a[i]=malloc(n * sizeof(int));
A:
int **a = malloc(m * sizeof(*a));
a[i]=malloc(n * sizeof(*(a[i])));
¿Qué está haciendo esto? El compilador sabe que a
es un int **
, por lo que puede
determine que sizeof(*a)
es lo mismo que sizeof(int *)
. Sin embargo, si
más tarde cambias de opinión y quieres char
s o short
s o long
s o
lo que sea en su matriz en lugar de int
s, o adaptar este código para más tarde
use en otra cosa, tendrá que cambiar solo el que queda
referencia a int
en la primera línea citada arriba, y todo else
automáticamente caerá en su lugar para usted. Esto elimina la probabilidad
de errores inadvertidos en el futuro.
¡Buena suerte!
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-14 10:59:45
Deshacer exactamente lo que ha asignado:
for (i = 0; i < m; i++) {
free(a[i]);
}
free(a);
Tenga en cuenta que debe hacer esto en el orden inverso desde el que originalmente asignó la memoria. Si lo hizo free(a)
primero, entonces a[i]
estaría accediendo a la memoria después de que se hubiera liberado, lo cual es un comportamiento indefinido.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-14 10:16:51
Necesita iterar nuevamente la matriz y hacer tantos frees como mallocs para la memoria apuntada, y luego liberar la matriz de punteros.
for (i = 0; i < m; i++) {
free (a[i]);
}
free (a);
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-14 10:23:27
Escriba sus operadores de asignación en orden exactamente inverso, cambiando los nombres de las funciones, y estará bien.
//Free the arrays
for (i = m-1; i >= 0; i--) {
free(a[i]);
}
free(a);
Por supuesto, no tienes que desasignar en el mismo orden inverso. Solo tienes que hacer un seguimiento de cómo liberar la misma memoria exactamente una vez y no "olvidar" los punteros a la memoria asignada (como habría sido si hubieras liberado el a
primero). Pero la desasignación en el orden inverso es un buen papel del pulgar para abordar este último.
Como apuntado by litb in the comments, if allocation / deallocation had side-effects (like new
/delete
operadores en C++), a veces el orden hacia atrás de la desasignación sería más importante que en este ejemplo en particular.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-05-23 12:10:31
Llamaría a malloc() y free () solo una vez:
#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;
}
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2009-11-14 10:40:08