Manière optimale de libérer () un tableau 2D mallocé en C

En supposant que j’ai un tableau en 2 dimensions qui a été créé avec quelque chose comme ça,

char **foo = (char **) malloc(height * sizeof(char *)); for(i = 0; i <= height; i++) foo[i] = (char *) malloc (width * sizeof(char *)); 

Tout d’abord, est-ce même la bonne façon de créer un tableau comme celui-ci ?. Le problème ici est que «hauteur» et «largeur» sont définis pendant l’exécution.

Cela semble fonctionner, mais quelle est la meilleure stratégie pour libérer ce tableau 2D. free (funge) ne sonne pas bien. En passant par d’autres posts ici, je suppose que chaque rangée sera libérée une par une?

J’ai essayé quelque chose comme ça,

 for (height = 0; height funge_height; height++) { free(funge[height]); } free(funge) 

Cela me donne toutefois une double exception de pointeur libre. Est-ce que cela signifie que je n’ai pas à gérer ce morceau de mémoire? J’avais l’impression que, pour chaque mémoire en mallocage, nous devrions appeler free ().

Étant donné que toutes les «lignes» ont la même taille, vous pouvez simplement les allouer en une fois, avec malloc(height * width * sizeof (char *)) (il n’est pas tout à fait clair si vous créez un tableau char 2ème tableau de char * ). Vous pouvez utiliser la multiplication pour calculer l’indice approprié (ie foo[i][j] devient foo + i * height + j ),

free() il sera pareillement, prendre un seul appel.

Dans la boucle d’allocation, vous utilisez i <= height; au lieu de i < height; . Donc, vous écrivez dans un emplacement mémoire invalide et le comportement de votre code devient imprévisible.

La deuxième allocation devrait être:

 foo[i] = (char *) malloc (width * sizeof(char)); 

vous faites également une boucle en height+1 fois lors de l’allocation.

En plus de cela, ces deux extraits me semblent corrects, l’erreur devrait donc être ailleurs.

Si le tableau était alloué comme un gros bloc de mémoire, vous deviez le libérer une seule fois.

 char **foo = (char **) malloc(height * sizeof(char *)); *foo = malloc(height * width * sizeof(char)) for (int i = 1; i < height; i++) { foo[i] = *foo + i*width; } //and you just do 2 frees free(*foo); free(foo); 

Le mécanisme d’allocation est correct (vous devez utiliser sizeof(char) au lieu de sizeof(char *) dans la boucle allocate; vous sur-localisez les chaînes de caractères) étant donné que la largeur et la hauteur sont des valeurs d’exécution.

Votre impression que vous devez appeler free () une fois pour chaque malloc () est fondamentalement correcte (des choses comme calloc () et realloc () compliquent l’histoire simple).

La boucle suivie de free devrait être correcte (ou, au moins, le mécanisme général consistant à libérer les sous-tableaux en premier lieu, puis le tableau des pointeurs sur les sous-tableaux) – vous devez donc indiquer d’où provient la double erreur free. . Nous ne pouvons pas voir où ip_ptr->funge_height était contrôlé; il n’est pas immédiatement évident que funge soit décrit par ip_ptr->funge_height .


Voir la réponse de ‘unknown @ google’ – il y a un problème de limite de tableau.

Lorsque vous allouez de la mémoire, la condition de boucle doit être i < height .

Lorsque vous libérez la mémoire, vous devriez effectuer une itération jusqu'au même index que lors de l'allocation. ip_ptr->funge_height devrait être identique à la height origine, mais ce n'est évidemment pas le cas.

Sinon, ça devrait marcher.

Voici une autre façon, qui implique moins de mallocs et libère.

Allouer:

 char **foo = malloc (height * sizeof (char **)); foo[0] = malloc (height * width * sizeof (char *)); for (i = 1; i < height; ++i) { foo[i] = foo[i-1] + width; } 

Pour désallouer:

 free (foo[0]); free (foo); 

Allocation (en supposant hauteur> 0 et largeur> 0)

 char **foo, *row; assert(height > 0 && width > 0); foo = malloc(height * sizeof *foo); row = malloc(height * width * sizeof *row); assert(foo != NULL && row != NULL); for (i = 0; i < height; ++i, row += width) foo[i] = row; assert(row == *foo + height * width); 

Deallocation

 assert(foo != NULL); free(*foo); free(foo); 

Dans de tels cas, vous pouvez toujours utiliser valgrind. Il suffit de comstackr votre exécutable et de le lancer:

 valgrind --leak-check=full ./a.out 

Valgrind trouvera toutes vos validations de mémoire et pointera sur les lignes de code impliquées.

Dans votre cas, le problème d’indexation (

Si votre compilateur le prend en charge, vous pouvez utiliser un pointeur sur un tableau de longueur variable, c’est-à-dire

 size_t width = 10, height = 5; char *(*foo)[height][width] = malloc(sizeof *foo); 

N’oubliez pas que vous devrez déréférencer le pointeur avant d’accéder aux éléments du tableau, par exemple

 (*foo)[1][2] = "foo"; 

Cela a pour avantage que vous n’allouerez qu’un seul bloc de mémoire continu qui peut être libéré avec un seul appel à free() .

Ce 100% fonctionne sans crash exe.

 char **map2d; map2d=(char **)malloc(MAXY*sizeof(char *)); for(int a=0; a