web-dev-qa-db-fra.com

Comment vérifier si un pointeur est déjà libéré en C?

Je voudrais vérifier si un pointeur est déjà libéré ou non. Comment est-ce que je fais ceci en utilisant le compilateur gnu? 

24
Kitcha

Tu ne peux pas. La façon de suivre cela serait d’attribuer le pointeur à 0 ou NULL après l’avoir libéré. Cependant, comme Fred Larson l'a mentionné, cela ne fait rien aux autres indicateurs pointant vers le même endroit.

int* ptr = (int*)malloc(sizeof(int));
free(ptr);
ptr = NULL;
25
Chad

Tu ne peux pas. Attribuez-lui simplement NULL après free pour vous assurer de ne pas le libérer deux fois (ok pour free(NULL)).

Mieux encore, n'écrivez pas de code si vous oubliez que vous l'avez déjà libéré.

MODIFIER

Interpréter la question comme suit: comment savoir si la mémoire indiquée par un pointeur est déjà libre: vous ne pouvez pas le faire. Vous devez faire votre propre comptabilité.

23
cnicutar

Il n'y a pas de moyen fiable de savoir si un pointeur a été libéré, comme l'a commenté Greg, la mémoire libérée pourrait être occupée par d'autres données non pertinentes et vous obtiendrez un résultat erroné.

Et en effet, il n’existe aucun moyen standard de vérifier si un pointeur est libéré. Cela dit, glibc a des fonctions (mcheck, mprobe) pour rechercher le statut malloc d'un pointeur pour vérification de la cohérence des segments , et l'une d'entre elles consiste à voir si un pointeur est libéré.

Cependant, ces fonctions sont principalement utilisées pour le débogage et elles ne sont pas thread-safe . Si vous n'êtes pas sûr du besoin, évitez ces fonctions. Assurez-vous simplement que vous avez associé malloc/free.


Exemple http://ideone.com/MDJkj :

#include <stdio.h>
#include <stdlib.h>
#include <mcheck.h>

void no_op(enum mcheck_status status) {}

int main()
{
    mcheck(&no_op);

    void* f = malloc(4);

    printf("%d (should be %d)\n", mprobe(f), MCHECK_OK);
    printf("%d (should be %d)\n", mprobe(f), MCHECK_OK);

    free(f);

    printf("%d (should be %d)\n", mprobe(f), MCHECK_FREE);
    printf("%d (should be %d)\n", mprobe(f), MCHECK_FREE);

    return 0;
}
14
kennytm

Vous pouvez étendre le concept d'attribution de NULL à la valeur du pointeur en écrivant une macro qui le fait pour vous. Par exemple:

#define FREE(ptr) do{ \
    free((ptr));      \
    (ptr) = NULL;     \
  }while(0)

Ensuite, tant que vous vous assurez que votre code utilise uniquement FREE () et non free (), vous pouvez être assez sûr que le code que vous avez écrit ne libère pas la même mémoire deux fois. Bien entendu, cela n'empêche pas plusieurs appels dans les fonctions de bibliothèque libérant de la mémoire. Et cela ne garantit en rien qu’il existe une gratuité pour chaque malloc. 

Vous pouvez essayer ceci avec une fonction, mais cela devient difficile parce que vous devez ajouter un opérateur de référence et que cela ne ressemble plus à un appel normal à free ().

4
Brian McFarland

Vous ne le faites pas, puisque vous ne pouvez pas.

Gardez une trace des pointeurs que vous obtenez de malloc() et libérez-les seulement, et une seule fois.

Si vous voulez, la mémoire n'a pas de mémoire, donc elle ne sait pas si elle est allouée ou non. Seul le gestionnaire de mémoire de votre système d'exploitation peut vous le dire (mais C n'inclut aucun mécanisme standardisé permettant d'interroger ces informations).

2
Kerrek SB

Je sais que cette réponse est a little bit tardive, mais je viens de lire cette réponse et j'ai écrit du code pour Vérifiez les éléments suivants:

Free mettra le bloc de mémoire dans sa propre liste de blocs libres. Normalement, il essaie également de fusionner des blocs adjacents dans l'espace d'adressage. La liste de blocage libre est juste une liste circulaire de morceaux de mémoire qui ont bien sûr quelques données administratives au début . La liste libre est aussi le premier emplacement, malloc cherche un nouveau bloc de mémoire en cas de besoin. Il est analysé avant d'appeler une nouvelle mémoire de l'OS. Lorsqu'un morceau trouvé est plus grand que la mémoire nécessaire, il est simplement divisé en deux parties. L'un est renvoyé à l'appelant, l'autre est remis dans la liste des numéros disponibles.

Ce code vérifie uniquement si le premier pointeur alloué est libéré:

int is_freed(void *p)
{
    void * q;
    char p_addr [50];
    char q_addr [50];

    sprintf(p_addr, "%p", p);

    q = malloc (1);
    sprintf(q_addr, "%p", q);
    free (q);

    return ! strcmp(q_addr, p_addr);
}

J'ai testé ce code sur HP-UX et Linux Redhat et cela fonctionne, dans le cas d'un seul pointeur.

0
Mansuro