12
votes

Libérer des pointeurs de l'intérieur d'autres fonctions en c

Considérez le code C:

void mycode() {
  MyType* p = malloc(sizeof(MyType));
  /* set the values for p and do some stuff with it */
  cleanup(p);
}


void cleanup(MyType* pointer) {
  free(pointer);
  pointer = NULL;
}


0 commentaires

6 Réponses :


20
votes

oui qui libérera la mémoire correctement.

pointeur à l'intérieur de la fonction de nettoyage est une variable locale; Une copie de la valeur passée dans les stockages stockés localement pour une seule fonction.

Ceci pourrait ajouter à votre confusion, mais vous pouvez ajuster la valeur de la variable p du à partir du MyCode Méthode, comme: xxx

Dans ce cas, pointeur stocke l'adresse du pointeur. Par la déséroférience que, vous pouvez modifier la valeur stockée à cette adresse.

Je remarquerai qu'il est généralement une bonne pratique de faire face à l'allocation et à la répartition du même «niveau» logique du logiciel - c'est-à-dire que Don ' t Faites-vous la responsabilité des appelants de répartir la mémoire, puis de libérer les fonctions intérieures. Conservez-le cohérent et au même niveau.


1 commentaires

Vous manquez de dire que cet appel doit être Nettoyage (& P);



12
votes

Nettoyage sera correctement libéré p , mais cela ne changera pas sa valeur. C est une langue de valeur transparente, vous ne pouvez donc pas modifier la variable de l'appelant de la fonction appelée. Si vous souhaitez définir p de nettoyer , vous devez faire quelque chose comme: xxx

et appelez-le comme: xxx

Votre code est un peu non idiomatique, pouvez-vous expliquer un peu mieux pourquoi vous souhaitez écrire ce Nettoyage Fonction? < / p>


0 commentaires

6
votes

oui

oui

oui: Il existe un bloc de mémoire produit par magie par MALLOC (3). Vous avez attribué l'adresse de cette mémoire, mais pas la mémoire elle-même de manière significative, au pointeur p qui est une variable auto dans mycode () < / code>.

Ensuite, vous passez p à nettoyer () , par valeur, qui copiera le pointeur et, à l'aide de la copie locale sur Nettoyage () , libérer le bloc. Nettoyage () Définit ensuite la propre instance du pointeur sur NULL, mais cela est inutile. Une fois la fonction remplie, le paramètre pointeur cesse d'exister.

BACK IN MYCODE () , vous avez toujours le pointeur p Tenir une adresse, mais le bloc est maintenant sur la liste gratuite et n'est pas terriblement utile pour le stockage jusqu'à ce qu'il soit à nouveau alloué .

Vous remarquerez peut-être que vous pouvez même stocker encore et lire à partir de * p, mais diverses quantités de perte en aval se produiront, car ce bloc de mémoire appartient maintenant à la bibliothèque et vous pouvez corrompre ses structures de données ou les données d'un futur propriétaire d'un bloc Malloc ().

La lecture attentive sur C peut vous donner une idée abstraite de la durée de vie variable, mais il est beaucoup plus facile de visualiser la mise en œuvre de la mise en œuvre de la répartition des paramètres et de la variable locale comme opérations de pile. Il est utile de suivre un cours d'assemblage avant le cours C.


3 commentaires

Hehehe ... Non, j'étais sérieux. En fait, j'ai commencé une longue réponse, mais j'ai décidé de le laisser tomber, car il s'agissait davantage de savoir comment l'enseignement de la programmation est passée de bas en haut (le meilleur moyen d'imo) de haut en bas (cela ne fonctionne pas bien, fondamentalement parce que n'est pas un sommet) à recharger (c.-à-d. Partir de laid de choses comme Java et d'aller nulle part). Je crois vraiment que les pointeurs sont morts simples, mais seulement si vous avez une saisie ferme de la façon dont un ordinateur fonctionne (un assemblage simple est un bon point de départ). Sans cette programmation de base devient juste un énorme tas de mots magiques avec des propriétés étranges.


@ 6502: Je suis totalement d'accord - le "Guide de l'utilisateur" pour le C64 était génial.


@ 6502, bien sûr, de bons points. Mais ce que j'ai "obtenu" était votre nom d'utilisateur. Bon choix.



3
votes

Ceci ne fonctionnera pas comme le pointeur code> dans code> dans Nettoyage () code> est local et l'attribuant ainsi null code> n'est pas vu par l'appelant fonction. Il y a deux façons courantes de résoudre ce problème.

  1. Au lieu d'envoyer le nettoyage du pointeur, envoyez-le un pointeur au pointeur. Ainsi modifier Nettoyage () code> comme suit: li> ol>
    void cleanup(MyType** pointer)
    {
      free(*pointer);
      *pointer = NULL;
    }
    


0 commentaires

1
votes

Il y a deux questions sont ici:

je me trompe en pensant qu'après nettoyage (p); est appelé, le contenu de p devrait maintenant être nul?

Oui, c'est faux. Après avoir appelé gratuit la mémoire pointée par le pointeur est compensée. Cela ne signifie pas que le contenu pointé par le pointeur est réglé sur NULL. En outre, si vous attendez que le pointeur p devienne null dans mycode Cela ne se produit pas parce que vous passez copie de p à Nettoyage . Si vous voulez p pour être null dans mycode , vous avez besoin d'un pointeur sur le pointeur dans Nettoyage , c'est-à-dire la signature de nettoyage serait Nettoyage (mytype **) .

Deuxième question:

nettoyage (mytype * pointeur) correctement Gratuit l'allocation de mémoire?

Oui, puisque vous faites gratuit sur un pointeur renvoyé par malloc la mémoire sera libérée.


0 commentaires

1
votes

Ce n'est pas juste vous.

Nettoyage () code> va bien nettoyer votre allocation, mais ne définira pas le pointeur sur null code> (qui devrait être considéré comme étant Séparez du nettoyage.) Les Data Les points de pointeur sur em> sont transmis à nettoyer () code> par pointeur et sont libres () code> ed correctement, mais le pointeur lui-même em> est passé par valeur, alors lorsque vous l'avez défini sur null code> Vous n'affectant que la copie locale (code> de la fonction de la fonction Pointeur, pas le pointeur d'origine. P>

Il y a trois façons autour de ceci: p>

  1. Utilisez un pointeur sur un pointeur. P> XXX PRE> LI>

  2. Utilisez une macro. P>

    void cleanup_func(struct MyType *p) { /* more complicated cleanup */ }
    #define cleanup(p) do { cleanup_func(p); p = NULL; } while(0)
    


0 commentaires