FAQ CConsultez toutes les FAQ
Nombre d'auteurs : 35, nombre de questions : 194, dernière mise à jour : 18 février 2018 Ajouter une question
Cette FAQ a été réalisée à partir des questions fréquemment posées sur les forums de www.developpez.com et de l'expérience personnelle des auteurs.
Je tiens à souligner que cette FAQ ne garantit en aucun cas que les informations qu'elle propose sont correctes ; les auteurs font le maximum, mais l'erreur est humaine. Cette FAQ ne prétend pas non plus être complète. Si vous trouvez une erreur, ou que vous souhaitez devenir rédacteur, lisez ceci .
Sur ce, je vous souhaite une bonne lecture.
- Faut-il toujours libérer la mémoire allouée dynamiquement ?
- Que contient ma mémoire après son allocation ?
- Que vaut un pointeur après free() ?
- Comment connaître la taille d'un tableau dynamique ?
- Comment allouer dynamiquement un tableau à 2 dimensions ?
- Quelle est l’utilité de realloc ?
- Comment (bien) utiliser realloc ?
Il faut toujours libérer les ressources que l'on a allouées. À chaque malloc ou calloc doit correspondre un et un seul free.
Certains systèmes libèrent automatiquement de telles ressources à la fin de l'exécution du programme. Toutefois ce comportement n'est pas garanti et la libération, si elle a lieu, est faite uniquement lors de l'arrêt du programme, il convient donc de ne pas compter sur cet effet de bord et libérer soi-même les différentes ressources allouées.
Si la mémoire a été allouée avec malloc, elle contient… n'importe quoi. En effet, malloc ne fait qu'allouer de la mémoire, mais ne l'initialise pas. Pour initialiser la zone mémoire, on peut utiliser calloc qui remplit la mémoire allouée de 0. On peut aussi l'initialiser soi-même, mais le résultat est le même.
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | #include <stdlib.h> #include <string.h> ... char * p = malloc(16); /* allocation d'une mémoire de 16 octets */ if (p != NULL) { memset(p, 0x00, 16); /* initialisation de la mémoire allouée */ ... free(p); } |
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 | #include <stdlib.h> ... char * p = calloc(16, sizeof(char)); /* allocation d'une mémoire initialisée (16 octets) */ if (p != NULL) { ... free(p); } |
Le pointeur reste inchangé (en effet il est passé par valeur à free), mais la mémoire qu'il pointe ne doit plus être utilisée par le programme (on dit que la mémoire a été « libérée »).
Une bonne habitude à prendre est de mettre tout pointeur libre à NULL :
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 | char * p = malloc(10); ... free(p); /* p ne sert plus a rien (pour le moment ...), mettons-le à NULL */ p = NULL; |
Il n'existe pas en C de fonction permettant de connaître la taille d'un tableau alloué dynamiquement, il faut donc impérativement conserver la taille de chaque tableau alloué. Une implémentation particulière peut cependant fournir une fonction permettant d'obtenir cette information (la fonction _msize sous Windows par exemple).
Si on désire allouer un tableau de N * M éléments, il y a deux méthodes possibles.
- On alloue un tableau de N pointeurs vers des tableaux de M éléments chacun.
Code C : | Sélectionner tout |
1 2 3 4 5 6 | /* On veut avoir int * tab[N], sauf que tab sera créé dynamiquement */ int ** tab = malloc(N * sizeof(int *)); /* On crée maintenant les N tableaux de M éléments chacun */ for(i = 0; i < N; i++) tab[i] = malloc(M * sizeof(int)); |
- On alloue réellement un tableau de N * M éléments.
Code C : | Sélectionner tout |
int * tab = malloc(N * M * sizeof(int));
realloc() permet de changer la taille du segment mémoire alloué avec malloc() (ou calloc()) pointé par un pointeur. Par exemple, pour un tableau dynamique pTab de dix entiers, grâce à realloc, vous pouvez l’agrandir pour qu’il contienne vingt entiers :
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 | int* pTab = malloc(10 * sizeof *pTab); // malloc peut aussi renvoyer NULL, n’oubliez pas de vérifier sa valeur de retour. int* pBigTab = realloc(pTab, 20 * sizeof *pTab) ; if(pBigTab) { // Utilisation de pBigTab, le tableau avec la nouvelle taille free(pBigTab); } else { // Utilisation de pTab, avec une taille inchangée free(pTab); } |
Déjà, on remarque que le code est plus compliqué que prévu. Vous pouvez comprendre la raison, dans cette Q/R.
Comme on peut le voir dans l’entrée de FAQ précédente, realloc() possède de nombreux cas à gérer. Énumérons-les :
- si la taille passée à realloc() est de 0, le comportement est déterminé par l’implémentation (et peut donc différer suivant les environnements de compilation) ;
- si le pointeur passé à realloc() est NULL, realloc() est équivalent à malloc() ;
- si realloc() ne peut allouer de la mémoire, il retourne NULL et laisse le pointeur d’origine intouché (non libéré, non modifié) ;
- autrement, realloc() alloue une nouvelle zone mémoire, de la taille souhaitée, y copie N octets (le minimum entre la taille de l’ancienne zone mémoire et la taille nouvellement demandée) provenant du pointeur d’origine et libère le tableau d’origine.
Une particularité de realloc() est que le pointeur retourné peut être le pointeur passé en paramètre et c’est de cette particularité que des erreurs de programmation en découlent. Il faut bien comprendre ici, que realloc() peut (mais n’est pas obligé) renvoyer le pointeur passé.
Surtout, il faut bien gérer tous les cas, pour éviter une quelconque erreur de segmentation (et faille de sécurité).
Reprenons le code précédent et décortiquons-le :
Code C : | Sélectionner tout |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | int taille = 10; int* pTab = malloc(10 * sizeof *pTab); int* pBigTab = realloc(pTab, 20 * sizeof *pTab); if(pBigTab) // Si realloc retourne un pointeur valide (non nul), alors, la mémoire de pTab a été libérée, on peut écraser { pTab = pBigTab; // Si jamais realloc() a réutilisé le segment mémoire pointé par pTab, cette opération est neutre, car les deux variables ont la même valeur. taille = 20; } else { // La réallocation n’a pu avoir lieu. La taille du tableau est donc inchangée. } // Utilisation du tableau pTab // Si realloc() a retourné NULL, nous ne passons pas dans le bloc précédent, mais pTab a été inchangé, donc nous devons libérer la mémoire pointée par pTab free(pTab); |
En résumé, il ne faut jamais faire :
Code C : | Sélectionner tout |
pTab = realloc(pTab, 10);
Aussi, si vous utilisez realloc(), il faut bien faire attention à ne pas faire de copie des pointeurs, car ceux-ci peuvent pointer vers une zone mémoire invalide suite à un realloc().
Proposer une nouvelle réponse sur la FAQ
Ce n'est pas l'endroit pour poser des questions, allez plutôt sur le forum de la rubrique pour çaLes sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2024 Developpez Developpez LLC. Tous droits réservés Developpez LLC. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents et images sans l'autorisation expresse de Developpez LLC. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.