FAQ CConsultez toutes les FAQ

Nombre d'auteurs : 34, 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.


SommairePointeurs, tableaux et chaînes de caractèresL'allocation dynamique de mémoire (7)
précédent sommaire suivant
 

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.

Mis à jour le 2 mars 2003 gl LFE

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); 
}
Ou :

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

Mis à jour le 1er février 2003 gl LFE PRomu@ld

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;
Ce qui provoque, en cas d'accès à p, une erreur systématique qui est plus simple à corriger qu'un programme au comportement erratique.

Mis à jour le 1er février 2003 gl LFE

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).

Mis à jour le 20 septembre 2004 gl haypo

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));
En fait, cette méthode ne crée pas vraiment un tableau de N * M entiers, mais un tableau de N pointeurs, chaque pointeur pointant vers un tableau de M entiers. L'avantage, c'est que l'accès à un "élément" de ce tableau se fait comme si le tableau était réellement un tableau « à deux dimensions » : tab[j][i] = ...;. L'inconvénient, c'est qu'elle est plus difficile à mettre en œuvre par rapport à l'autre méthode.

- On alloue réellement un tableau de N * M éléments.

Code C : Sélectionner tout
int * tab = malloc(N * M * sizeof(int));
L'avantage, c'est que c'est simple à mettre en œuvre. L'inconvénient, c'est que l'accès à un élément du tableau ne se fait pas aussi aisément qu'avec l'autre méthode : tab[M * j + i] = ...;.

Mis à jour le 1er février 2003 LFE

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.

Mis à jour le 18 février 2018 LittleWhite Mat.M theludovyc

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);
Sinon, vous avez un risque de fuite de mémoire (par perte de la variable pointée sur une zone allouée).
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().

Mis à jour le 18 février 2018 LittleWhite Mat.M theludovyc

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 ça


Réponse à la question

Liens sous la question
précédent sommaire suivant
 

Les 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 © 2018 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.

 
Contacter le responsable de la rubrique C