web-dev-qa-db-fra.com

C - libérer des structures

Disons que j'ai cette structure

typedef struct person{
    char firstName[100], surName[51]
} PERSON;

et j'alloue de l'espace par malloc et le remplit avec quelques valeurs

PERSON *testPerson = (PERSON*) malloc(sizeof(PERSON));
strcpy(testPerson->firstName, "Jack");
strcpy(testPerson->surName, "Daniels");

Quel est le moyen correct et sûr de libérer toute la mémoire prise par cette structure? Est "gratuit (testPerson);" assez ou dois-je libérer chaque attribut de struct?

Cela m'amène à une autre question: comment les structures sont-elles stockées dans la mémoire? J'ai remarqué un comportement étrange: lorsque j'essaie d'imprimer une adresse de structure, elle est égale à l'adresse de son premier attribut.

printf("Structure address %d == firstName address %d", testPerson, testPerson->firstName);

Ce qui signifie que ce libre (testPerson) doit être égal à ce libre (testPerson-> firstName);

et ce n'est pas ce que je veux faire.

Merci

44
user10099

Réponse simple: free(testPerson) suffit.

N'oubliez pas que vous ne pouvez utiliser free() que lorsque vous avez alloué de la mémoire à l'aide de malloc, calloc ou realloc.

Dans votre cas, vous n’avez que de la mémoire mallocalisée pour testPerson et le libérer est donc suffisant.

Si vous avez utilisé char * firstname , *last surName, Dans ce cas, pour stocker le nom, vous devez avoir alloué la mémoire et vous devez donc libérer chaque membre individuellement.

Voici aussi un point qui devrait être dans l’ordre inverse; cela signifie que la mémoire allouée aux éléments est effectuée ultérieurement, donc free() libère ensuite le pointeur sur object.

En libérant chaque élément, vous pouvez voir la démo ci-dessous:

typedef struct Person
{
char * firstname , *last surName;
}Person;
Person *ptrobj =malloc(sizeof(Person)); // memory allocation for struct
ptrobj->fistname = malloc(n); // memory allocation for firstname
ptrobj->surName = malloc(m); // memory allocation for surName

.
. // do whatever you want

free(ptrobj->surName);
free(ptrobj->firstname);
free(ptrobj);

La raison derrière ceci est que, si vous libérez d'abord le ptrobj, il y aura une fuite de mémoire, c'est-à-dire la mémoire allouée par les pointeurs firstname et suName.

59
Omkant

Étant donné que vous avez défini le struct comme étant constitué de tableaux char, les deux chaînes are la structure et le fait de libérer le struct sont suffisants. moyen de libérer le struct mais gardez les tableaux. Dans ce cas, vous voudriez faire quelque chose comme struct { char *firstName, *lastName; }, mais vous devez ensuite allouer de la mémoire pour les noms séparément et régler la question de savoir quand libérer that memory.

De plus, y a-t-il un motif vous voulez conserver les noms après la libération de struct?

5
dmckee

Tout d'abord, vous devez savoir combien de mémoire est allouée lorsque vous définissez et allouez de la mémoire dans le cas ci-dessous.

   typedef struct person{
       char firstName[100], surName[51]
  } PERSON;
  PERSON *testPerson = (PERSON*) malloc(sizeof(PERSON));

1) Le sizeof (PERSON) renvoie maintenant 151 octets (n'inclut pas le remplissage)

2) La mémoire de 151 octets est allouée dans le tas.

3) Pour libérer, appelez gratuitement (testPerson).

mais si vous déclarez votre structure comme

  typedef struct person{
      char *firstName, *surName;
  } PERSON;
  PERSON *testPerson = (PERSON*) malloc(sizeof(PERSON));

puis

1) Le sizeof (PERSON) renvoie maintenant 8 octets (n'inclut pas le remplissage)

2) Besoin d'allouer de la mémoire pour firstName et surName en appelant malloc () ou calloc (). comme

        testPerson->firstName = (char *)malloc(100);

3) Pour libérer, commencez par libérer les membres de la structure, puis libérez-la. c'est-à-dire libre (testPerson-> firstName); libre (testPerson-> surName); libre (testPerson);

4
Viswesn

De cette façon, il vous suffit de libérer la structure car les champs sont des tableaux de tailles statiques qui seront alloués dans le cadre de la structure. C'est aussi la raison pour laquelle les adresses que vous voyez correspondent: le tableau est la première chose dans cette structure. Si vous déclarez les champs comme char *, vous devrez manuellement malloc et les libérer.

3
MK.

Les mallocs et les libérés doivent être jumelés.

malloc a saisi un morceau de mémoire assez gros pour Person.

Lorsque vous libérez, vous indiquez à malloc que la mémoire commençant par "ici" n’est plus nécessaire, elle sait combien de temps elle a allouée et la libère.

Si vous appelez

 free(testPerson) 

ou

 free(testPerson->firstName)

tout ce que free () reçoit réellement est une adresse, la même adresse, elle ne peut pas dire laquelle vous avez appelée. Votre code est beaucoup plus clair si vous utilisez free (testPerson) - il correspond clairement à celui de malloc.

2
djna

Vous ne pouvez pas libérer des types qui ne sont pas alloués dynamiquement. Bien que les tableaux soient syntaxiquement similaires (int* x = malloc(sizeof(int) * 4) peut être utilisé de la même manière que int x[4] Est), appeler free(firstName) provoquerait probablement une erreur pour ce dernier.

Par exemple, prenons ce code:

int x;
free(&x);

free() est une fonction qui prend un pointeur. &x Est un pointeur. Ce code peut compiler, même s'il ne fonctionne tout simplement pas.

Si nous prétendons que toute la mémoire est allouée de la même manière, x est "alloué" à la définition, "libéré" à la deuxième ligne, puis "libéré" à la fin de la portée. Vous ne pouvez pas libérer deux fois la même ressource; ça va vous donner une erreur.

Cela ne mentionne même pas le fait que pour certaines raisons, vous ne pourrez peut-être pas libérer la mémoire à x sans fermer le programme.

tl; dr: Libérez simplement le struct et tout ira bien. Don't appelez gratuitement sur les tableaux; appelez-le uniquement sur la mémoire allouée dynamiquement.

2
Undeterminant

free ne suffit pas, free marque simplement la mémoire comme étant inutilisée, les données de structure y resteront jusqu'à ce qu'elles soient écrasées. Par sécurité, définissez le pointeur sur NULL après free.

Ex:

if (testPerson) {
    free(testPerson);
    testPerson = NULL;
}

struct ressemble à un tableau, c'est un bloc de mémoire. Vous pouvez accéder au membre struct via son offset. Le premier membre de la structure est placé à offset 0 donc l'adresse du membre de la première structure est la même que l'adresse de la structure.

2
sdao