Devrais-je libérer char * initialisé à l’aide de chaînes de caractères?

Devrais-je libérer les variables char* lorsqu’elles ont été initialisées à l’aide de chaînes de caractères? Pour moi, la syntaxe me conduirait à l’hypothèse qu’elles ne sont allouées que par stack, mais cet exemple m’a montré, elles ne le sont pas.

 #include  #include  static char* globalBuffer; typedef struct Container { char* buffer; } Container; Container* Container_new(char* buffer) { Container* container = malloc(sizeof(Container)); container->buffer = buffer; globalBuffer = buffer; return container; } void Container_print(Container* container) { if (container->buffer != NULL) { printf(container->buffer); printf("\n"); } else { printf("Container contains a NULL-buffer."); } } Container* stage() { Container* container = Container_new("Test-ssortingng."); Container_print(container); return container; } int main() { Container* container = stage(); Container_print(container); free(container); Container_print(container); // I know, this results in undefined behaviour printf(globalBuffer); printf("\n"); return 0; } 

Je reçois la sortie suivante:

 C:\Users\niklas\Desktop>gcc char_test.c C:\Users\niklas\Desktop>a.exe Test-ssortingng. Test-ssortingng. 6> Test-ssortingng. C:\Users\niklas\Desktop> 

Ainsi, le caractère char* initialisé avec les littéraux de chaîne existe toujours, même s’il est sorti de sa scope.

Alors, ma question, devrais-je libérer de tels indicateurs? Serait-ce la bonne main() ?

 int main() { Container* container = stage(); Container_print(container); free(container->buffer); // NEW free(container); Container_print(container); printf(globalBuffer); printf("\n"); return 0; } 

Les littéraux de chaîne sont stockés de manière à être disponibles pendant toute la durée du programme. si vous écrivez

 char *ptr = "This is a test"; 

tout ce qui est écrit dans ptr est l’ adresse du littéral de chaîne "This is a test" . Même si la variable ptr sort de la scope, le littéral chaîne continue d’exister dans sa propre section de mémoire, qui n’est pas la même que celle utilisée par malloc (du moins, pas à un niveau logique). Notez que plusieurs instances du même littéral de chaîne peuvent être résolues au même emplacement. IOW, étant donné

 char *p0 = "This is a test"; char *p1 = "This is a test"; 

p0 et p1 peuvent tous deux contenir la même adresse (le compilateur peut décider si plusieurs occurrences de littéraux de chaîne sont ou non mappées au même emplacement).

Lorsque vous appelez Container_new , vous ne faites que copier une adresse dans container->buffer et globalBuffer ; les deux finissent par indiquer la même chose qui existe indépendamment de l’un ou l’autre. free container n’affecte pas le littéral de chaîne pointé par container->buffer , donc printf(globalBuffer); affiche toujours "Test-ssortingng." .

En résumé, vous ne devriez pas appeler

 free(container->buffer); 

pour ce programme particulier, puisque vous n’avez pas atsortingbué le résultat d’un appel malloc , calloc ou realloc .

Si, OTOH, vous aviez écrit Container_new comme

 Container* Container_new(char* buffer) { Container* container = malloc(sizeof(Container)); container->buffer = malloc(strlen(buffer) + 1); // Allocate memory to if (container->buffer) // store a *new* instance { // of the input ssortingng. strcpy(container->buffer, buffer); // This will need to be } // freed before freeing globalBuffer = buffer; // the container return container; } 

alors vous auriez besoin de libérer le container->buffer avant de libérer le container .

Vous ne libérerez jamais free() mémoire que vous n’avez pas malloc() .

La manière dont le compilateur implémente les littéraux de chaîne n’est pas votre affaire: c’est un détail d’implémentation. Vous pouvez free() un pointeur sur la mémoire que vous avez alloué en utilisant malloc() , et seulement ceux-là, ou vous risquez la vie de votre système.

Idéalement, les appels malloc() et free() devraient apparaître au même “niveau de conception” (dans le même fichier d’implémentation pour le même module par exemple), et ils devraient correspondre parfaitement: un free() pour chaque malloc() . mais ce n’est pas toujours possible.

(Notez que certaines bibliothèques allouent des blocs de mémoire, renvoient des pointeurs à ces blocs et vous demandent de les libérer. Dans ce cas, vous êtes autorisé à libérer ces pointeurs, mais c’est une mauvaise pratique de conception de la part des personnes qui ont créé la bibliothèque. )