Affectation / désallocation de pointeur C de base

L’écriture de code en C, ne l’a jamais appris formellement, en utilisant la bibliothèque GSL de GNU, question fondamentale rapide

Corrigez-moi si je me trompe, mais si je comprends bien, lorsque je mets de la mémoire à utiliser pour mes masortingces (à l’aide de la var = gsl_masortingx_alloc(x,x) ) et que je les stocke dans une variable, je suis essentiellement créer un pointeur, qui est simplement une adresse de mémoire, comme: x01234749162

quels POINTS au premier pointeur / emplacement mémoire de ma masortingce GSL. Suivre le moment où libérer la mémoire de la structure associée à un pointeur (encore une fois, gsl_masortingx_free(x,x,x) ) n’est pas un problème, et je comprends que j’ai besoin de le faire avant de réaffecter le pointeur de la structure, sinon J’ai créé une fuite de mémoire.

Alors maintenant, pour ma question, et encore une fois, je sais que ceci est fondamental, mais écoutez-moi – je ne pouvais pas trouver une réponse particulièrement directe sur stackoverflow, principalement parce que beaucoup de réponses impliquent C ++ plutôt que C – comment puis-je libérer le pointeur sur la structure elle-même?

Tout le monde dit “oh, il suffit de le mettre à NULL”. Pourquoi cela fonctionnerait-il? Il ne s’agit que de changer l’adresse mémoire que POINTS a pour structure désallouée. Est-ce que cela indique à la MMU que cet emplacement de mémoire peut être utilisé maintenant? Lorsque je débogue mon programme dans XCode, par exemple, toutes les propriétés de la structure gsl_masortingx sont désallouées avec succès. tout devient simplement cette chaîne de caractères hexadécimaux aléatoires, ce que la mémoire libre est supposée faire. Mais, je peux toujours voir le nom de la variable (pointeur) tout en parcourant le débogueur … même si je règle la variable sur NULL. J’interprète cela comme signifiant que je n’ai pas libéré le pointeur, je viens de libérer la structure et de le définir sur x0000000 (NULL).

Est-ce que je fais tout correctement, et c’est juste une fonctionnalité de XCode, ou est-ce que je manque quelque chose de basique?

Et je me rends bien compte qu’un seul pointeur sur une structure, si celle-ci est désallouée, pourrait être considéré comme n’ayant pas beaucoup d’importance, mais c’est important.

Voici un code pour essayer d’illustrer mes pensées.

 gsl_masortingx* my_masortingx; // create single memory address in memory, not pointing to anything yet my_masortingx = gsl_masortingx_alloc(5, 5); // allocates 25 memory spaces for the values that the pointer held by my_masortingx // points too // Note: so, now there's 26 memory spots allocated to the masortingx, excluding other // properties created along with the my-masortingx structure, right? gsl_masortingx_free(my_masortingx); // deallocates those 25 spaces the structure had, // along with other properties that may have been automatically created free(my_masortingx); // SIGBRT error. Is the pointer to the deallocated structure // still using that one memory address? my_masortingx = NULL; // this doesn't make sense to me.I get that any future referral // to the my_masortingx pointer will just return garbage, and so setting a pointer to // that can help in debugging, but can the pointer--that is just one memory // address--be completely deallocated such that in the debugger the variable name // disappears? 

Tout le monde dit “oh, il suffit de le mettre à NULL”. Pourquoi cela fonctionnerait-il?

Cela signifie probablement que cela résoudrait le problème suivant: vous appelez free un pointeur vers des données déjà désaffectées, ce que vous faites ici:

 gsl_masortingx_free(my_masortingx); // deallocate free(my_masortingx); // Mistake, BIG PROBLEM: my_masortingx points to de-allocated data 

Cela corrige le problème car appeler free sur un null-ptr n’est pas un problème:

 gsl_masortingx_free(my_masortingx); // deallocate my_masortingx = NULL; free(my_masortingx); // Mistake, but no problem 

Remarque : my_masortingx lui-même le stockage automatique, il n’est donc pas nécessaire de le my_masortingx manuellement. Sa mémoire sera récupérée quand il sera hors de scope. La seule chose à my_masortingx est la mémoire allouée dynamicment (et sur laquelle pointe my_masortingx ).

Ce qui vous manque ici, c’est la connaissance du fonctionnement des “variables locales” au niveau de la machine et du concept de “stack”.

La stack est un bloc de mémoire libre allouée à votre programme lors de son démarrage. Supposons, à titre d’exemple simple, que votre programme se voit atsortingbuer une stack de taille 1MB. La stack est accompagnée d’un registre spécial appelé “pointeur de stack”, qui pointe initialement vers la fin de la stack (ne demandez pas pourquoi pas le début, raisons historiques). Voici à quoi ça ressemble:

  [---------- stack memory, all yours for taking ------------] ^ | Stack pointer 

Supposons maintenant que votre programme définisse un groupe de variables dans la fonction main , c’est-à-dire quelque chose comme:

  int main() { int x; 

Cela signifie que lorsque la fonction main est appelée au début de votre programme, le compilateur génère les instructions suivantes:

  sp = sp - 4; // Decrement stack pointer x_address = sp; 

et rappelez-vous (aux fins de compilation ultérieure) que x est maintenant un entier de 4 octets situé à la position mémoire x_address . Votre stack ressemble maintenant à ceci:

  [---------- stack memory, all yours for taking --------[-x--] ^ | Stack pointer 

Ensuite, supposons que vous appeliez une fonction f depuis le main. Supposons que f définisse en son sein une autre variable,

 int f() { char z[8]; 

Devinez ce qui se passe maintenant? Avant d’entrer f le compilateur effectuera:

 sp = sp - 8; z_address = sp; 

C’est à dire que vous aurez:

  [---------- stack memory, all yours for taking -[--z----][-x--] ^ | Stack pointer 

Si vous appelez maintenant une autre fonction, le pointeur de la stack se déplacera plus profondément dans la stack, “créant” plus d’espace pour les variables locales. Cependant, chaque fois que vous quittez une fonction, le pointeur de la stack est restauré à son emplacement antérieur à l’appel de la fonction. Par exemple, après avoir quitté f , votre stack se présentera comme suit:

  [---------- stack memory, all yours for taking -[--z----][-x--] ^ | Stack pointer 

Notez que le tableau z n’a pas été essentiellement libéré, il est toujours présent sur la stack, mais cela ne vous dérange pas. Pourquoi tu t’en fous? Parce que toute la stack est automatiquement désallouée lorsque votre application se termine. C’est la raison pour laquelle vous n’avez pas besoin de libérer manuellement les “variables sur la stack”, c’est-à-dire celles définies comme locales par vos fonctions et vos modules. En particulier, votre pointeur my_masortingx n’est qu’une variable de ce type.

  • PS: il y a un peu plus de choses sur la stack que ce que j’ai décrit. En particulier, la valeur du pointeur de stack est stockée sur la stack avant de la décrémenter, afin de pouvoir être restaurée après la sortie de la fonction. De plus, les arguments de fonction sont souvent passés en les plaçant dans la stack. En ce sens, elles ressemblent à des variables locales aux fins de la gestion de la mémoire et vous n’avez pas besoin de les libérer.

  • PPS: En principe, le compilateur est libre d’optimiser votre code (surtout si vous comstackz avec l’indicateur -O ) et, au lieu d’allouer vos variables locales sur la stack, il peut:

    • Décidez de ne pas les atsortingbuer du tout (par exemple, si elles s’avèrent inutiles)
    • Décidez de les allouer temporairement dans les registres (qui sont des emplacements de mémoire fixes dans le processeur qui n’ont pas besoin d’être libérés). Ceci est souvent fait pour les variables de boucle (celles dedans for (int i = ...) ).
    • .. et bien, faites tout ce qui lui passe par la tête, tant que le résultat ne contredit pas la sémantique.
  • PPPS: Vous êtes maintenant prêt à apprendre le fonctionnement du débordement de mémoire tampon . Allez lire à ce sujet, vraiment, c’est un truc incroyable. Oh, et une fois que vous y êtes, vérifiez le sens du débordement de stack . 😉

Pourquoi 26 emplacements mémoire seraient-ils alloués à une masortingce 5×5? Je dirais que vous feriez confiance à la fonction gsl_masortingx_free fournie par la bibliothèque pour faire le bon choix et libérer la structure entière.

En général, vous n’avez besoin d’appeler free si vous appelez malloc ou calloc . Les fonctions de bibliothèque qui fournissent un allocateur fournissent généralement un désallocateur correspondant, de sorte que vous n’avez pas à suivre les données internes.

Si le point 26 qui vous préoccupe est le pointeur lui-même (en d’autres termes, la mémoire nécessaire pour stocker l’adresse de la masortingce), cet espace fait partie du cadre de stack pour votre fonction et il est automatiquement supprimé lorsque la fonction résultats.