it-swarm.com.de

Wie kann man überprüfen, ob ein Zeiger bereits in C freigegeben ist?

Ich möchte prüfen, ob ein Zeiger bereits freigegeben ist oder nicht. Wie mache ich das mit dem gnu-Compilersatz? 

24
Kitcha

Du kannst nicht Dies können Sie verfolgen, indem Sie den Zeiger nach der Freigabe 0 oder NULL zuweisen. Wie Fred Larson jedoch erwähnt hat, wirkt sich dies nicht auf andere Zeiger aus, die auf dieselbe Position zeigen.

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

Du kannst nicht Weisen Sie einfach NULL zu, nachdem Sie free ausgewählt haben, um sicherzustellen, dass Sie es nicht zweimal freigeben (es ist ok für free(NULL)).

Besser noch, wenn möglich, schreiben Sie keinen Code, wo Sie "vergessen", dass Sie ihn bereits freigegeben haben.

BEARBEITEN

Interpretation der Frage als wie Sie herausfinden können, ob der Speicher, auf den ein Zeiger zeigt, bereits freigegeben ist : Sie können es nicht tun. Sie müssen Ihre eigene Buchhaltung machen.

23
cnicutar

Es gibt keine zuverlässige Methode, um zu ermitteln, ob ein Zeiger freigegeben wurde. Wie Greg kommentierte, könnte der freigegebene Speicher mit anderen irrelevanten Daten belegt sein und Sie erhalten ein falsches Ergebnis.

Tatsächlich gibt es keine Standardmethode, um zu überprüfen, ob ein Zeiger freigegeben wird. That said, glibc hat Funktionen (mcheck, mprobe), um den Malloc-Status eines Zeigers für Heap-Konsistenzprüfung zu ermitteln, und eine davon prüft, ob ein Zeiger freigegeben wird.

Allerdings werden diese Funktionen hauptsächlich nur zum Debuggen verwendet und sie sind nicht threadsicher . Wenn Sie sich der Anforderung nicht sicher sind, vermeiden Sie diese Funktionen. Stellen Sie nur sicher, dass Sie malloc/free gekoppelt haben.


Beispiel 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

Sie können das Konzept der Zuweisung von NULL zum Zeigerwert erweitern, indem Sie ein Makro schreiben, das dies für Sie erledigt. Zum Beispiel:

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

Solange Sie sicherstellen, dass Ihr Code nur FREE () und nicht Free () verwendet, können Sie ziemlich sicher sein, dass der von Ihnen geschriebene Code nicht zweimal denselben Speicher freigibt. Natürlich werden dadurch nicht mehrere Aufrufe von Bibliotheksfunktionen verhindert, die Speicherplatz freigeben. Und es garantiert nicht, dass es für jeden Malloc ein kostenloses Angebot gibt. 

Sie können dies mit einer Funktion versuchen, aber es wird schwierig, weil Sie einen Referenzoperator einschleusen müssen und es nicht mehr wie ein normaler Aufruf von free () aussieht.

4
Brian McFarland

Sie nicht, da Sie nicht können.

Verfolgen Sie die Zeiger, die Sie von malloc() erhalten, und geben Sie diese nur einmal frei.

Wenn Sie möchten, hat der Speicher kein Gedächtnis, daher weiß er nicht, ob er belegt ist oder nicht. Das kann nur der Speichermanager Ihres Betriebssystems sagen (aber C enthält keinen standardisierten Mechanismus zum Abfragen dieser Informationen).

2
Kerrek SB

Ich weiß, dass diese Antwort a little bit zu spät ist, aber ich las gerade diese Antwort und schrieb etwas Code an , Um Folgendes zu überprüfen:

Free legt den Speicherblock in seiner eigenen Liste der freien Blöcke ab. Normalerweise versucht es auch, benachbarte Blöcke im Adressraum zusammenzufügen. Die Liste der freien Blöcke ist nur eine zirkuläre Liste von Speicherblöcken, die am Anfang natürlich einige Admin-Daten haben. Die freie Liste ist auch der erste Ort, malloc sucht bei Bedarf nach einem neuen Speicherplatz. Es wird gescannt, bevor vom Betriebssystem neuer Speicher abgerufen wird. Wenn ein Block gefunden wird, der größer ist als der benötigte Speicher, wird er nur in zwei Teile aufgeteilt. Eine wird an den Anrufer zurückgegeben, die andere wird wieder in die freie Liste aufgenommen.

Dieser Code prüft nur, ob der erste zugewiesene Zeiger freigegeben wurde:

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);
}

Ich habe diesen Code auf HP-UX und Linux Redhat getestet und funktioniert nur für einen einzigen Zeiger.

0
Mansuro