C: Libérer correctement la mémoire d’un tableau multidimensionnel

Supposons que le code ANSI C suivant initialise un tableau multidimensionnel:

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; } 

Après avoir utilisé le **a , comment puis-je le libérer correctement de la mémoire?


[Mise à jour] (Solution)

Grâce à la réponse de Tim (et des autres), je peux maintenant exécuter une telle fonction pour libérer de la mémoire de mon tableau multidimensionnel:

 void freeArray(int **a, int m) { int i; for (i = 0; i < m; ++i) { free(a[i]); } free(a); } 

    OK, il y a beaucoup de confusion qui explique exactement dans quel ordre se trouvent les appels free() nécessaires, alors je vais essayer de clarifier ce que les gens essaient de savoir et pourquoi.

    Pour commencer, afin de libérer de la mémoire allouée avec malloc() , vous appelez simplement free() avec exactement le pointeur qui vous a été atsortingbué par malloc() . Donc pour ce code:

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

    vous avez besoin d’une correspondance:

     free(a); 

    et pour cette ligne:

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

    vous avez besoin d’une correspondance:

     free(a[i]); 

    dans une boucle similaire.

    Lorsque cela se complique, c’est l’ordre dans lequel cela doit se produire. Si vous appelez plusieurs fois malloc() pour obtenir plusieurs morceaux de mémoire, en général, l’ordre dans lequel vous appelez free() importe peu quand vous en aurez fini. Cependant, l’ordre est important ici pour une raison bien précise: vous utilisez un bloc de mémoire malloc ed pour conserver les pointeurs sur d’autres morceaux de mémoire malloc ed. Parce que vous ne devez pas essayer de lire ou d’écrire de la mémoire après l’avoir restituée avec free() , cela signifie que vous allez devoir libérer les morceaux avec leurs pointeurs stockés dans a[i] avant de libérer le morceau lui-même. Les morceaux individuels avec des pointeurs stockés dans a[i] ne sont pas dépendants les uns des autres et peuvent donc être free dans l’ordre de votre choix.

    Donc, en réunissant tout cela, nous obtenons ceci:

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

    Un dernier conseil: lorsque vous appelez malloc() , envisagez de les modifier:

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

    à:

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

    Qu'est-ce que ça fait? Le compilateur sait que a est un int ** et peut donc déterminer que sizeof(*a) est identique à sizeof(int *) . Cependant, si plus tard vous changez d’avis et voulez des caractères, short ou long ou quoi que ce soit dans votre tableau au lieu d’ int , ou si vous adaptez ce code pour un usage ultérieur, vous devrez changer celui qui rest. référence à int dans la première ligne citée ci-dessus, et tout le rest se mettra automatiquement en place pour vous. Cela supprime la probabilité d'erreurs inaperçues à l'avenir.

    Bonne chance!

    Annuler exactement ce que vous avez alloué:

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

    Notez que vous devez le faire dans l'ordre inverse de celui auquel vous avez initialement alloué la mémoire. Si vous libériez free(a) premier, a[i] accèderait à la mémoire une fois libérée, ce qui constitue un comportement indéfini.

    Vous devez réitérer le tableau et faire autant de libérations que de mallocs pour la mémoire pointée, puis libérer le tableau de pointeurs.

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

    Ecrivez vos opérateurs d’allocation dans un ordre exactement inversé, en changeant le nom des fonctions, et tout ira bien.

      //Free the arrays for (i = m-1; i >= 0; i--) { free(a[i]); } free(a); 

    Bien sûr, vous n’avez pas à désallouer dans le même ordre inversé. Vous devez simplement vous assurer de libérer la même mémoire une seule fois et non “d’oublier” les pointeurs vers la mémoire allouée (comme cela aurait été le cas si vous aviez libéré le premier). Mais désallouer dans l’ordre inverse est un bon rôle pour régler le problème.

    Comme l’a souligné litb dans les commentaires, si l’allocation / désallocation avait des effets secondaires (comme les opérateurs new / delete en C ++), l’ordre inverse de la désallocation serait parfois plus important que dans cet exemple particulier.

    J’appellerais malloc () et free () une seule fois:

     #include  #include  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