2014-07-24 13 views
5

Ich entwickle ein Projekt in C, und ich muss den zugewiesenen Speicher freigeben und auch alle geöffneten Dateien schließen, bevor es beendet wird.Gibt es eine Möglichkeit, Speicher in atexit oder ähnlichem freizugeben, ohne globale Variablen zu verwenden?

Ich entschied mich, eine clean Funktion zu implementieren, die all diese Sachen tun und es mit atexit aufrufen wird, weil es viele mögliche Ausgangsszenarien gibt.

Das Problem ist, dass atexit erlaubt mir nicht, Funktionen mit Parametern einzustellen, so kann ich nicht zu clean die Zeiger senden, die am Ende des Prozesses freigegeben werden müssen.

Also muss ich als globale Variablen jeden Zeiger, der möglicherweise freigegeben werden muss, und jede Datei, die möglicherweise im Programm geöffnet bleiben? (Ich habe das schon gemacht, sieht aber nicht gut aus) oder existiert eine ähnliche Funktion wie atexit, die es erlaubt Parameter zu senden? oder wahrscheinlicher gibt es einen anderen Weg, den ich vermisse?

+1

Sie benötigen nur eine Variable, die auf Ihren Speicherpool zeigt. Das scheint akzeptabel. – this

+2

Wenn Sie mit einem modernen Betriebssystem arbeiten, werden beim Beenden alle Ressourcen freigegeben. Das bedeutet, dass der gesamte zugewiesene Speicher freigegeben wird, alle geöffneten Dateien geschlossen werden usw. –

+1

Wenn Sie z. Dateien, die während der gesamten Prozesslaufzeit geöffnet sein müssen, dann greifen Sie wahrscheinlich auch an mehreren Stellen darauf zu, und das bedeutet, dass es bereits eine globale Variable oder zumindest global in einer Übersetzungseinheit ist und Sie dann eine Funktion zum Schließen haben können Diese Datei wird von einer globalen 'clean_all'-Funktion aufgerufen. Das Gleiche gilt für den Speicher, den Sie zuweisen. –

Antwort

4

einen statischen Zeiger in einer Funktion verwenden:

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

void atexit_clean(void *data); 

static void clean(void) 
{ 
    atexit_clean(NULL); 
} 

void atexit_clean(void *data) 
{ 
    static void *x; 

    if (data) { 
     x = data; 
     atexit(clean); 
    } else { 
     free(x); 
    } 
} 

int main(void) 
{ 
    int *a = malloc(sizeof(int)); 

    atexit_clean(a); 
    return 0; 
} 

Eine andere Methode eine einzige globale Variable: Sie alle Objekte in einem Array von Zeigern oder einer verknüpften Liste befreit speichern können werden, verwendet dieses Beispiel realloc (nicht überprüft (m/re) alloc der Kürze halber):

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

static void **vclean; 
static size_t nclean; 

void atexit_add(void *data) 
{ 
    vclean = realloc(vclean, sizeof(void *) * (nclean + 1)); 
    vclean[nclean++] = data; 
} 

void clean(void) 
{ 
    size_t i; 

    for (i = 0; i < nclean; i++) { 
     free(vclean[i]); 
    } 
    free(vclean); 
} 

int main(void) 
{ 
    int *a, *b, *c; 
    double *d; 
    int e = 1; 

    atexit(clean); 
    a = &e; 
    b = malloc(sizeof(int)); 
    atexit_add(b); 
    c = malloc(sizeof(int)); 
    atexit_add(c); 
    d = malloc(sizeof(double)); 
    atexit_add(d); 
    return 0; 
} 
+0

Sie sollten 'atexit (clean_all);' an den Anfang der 'main()' -Funktion verschieben. Für ein realistisches Beispiel könnte es Operationen geben, die das Programm zwischen den Aufrufen von 'atexit_add()' beenden. – kay

+0

@Kay, das hängt davon ab, ob Sie sauber gehen oder abbrechen wollen, aber im Allgemeinen haben Sie Recht, bearbeitet. –

+0

'atexit_add()' sollte auf 'realloc()' Fehler überprüfen und eine Fehlermeldung an den Aufrufer zurückgeben. –

3

Es gibt keine Art und Weise ist es, alle Parameter zu atexit() passieren, so dass Sie globale Variablen stecken verwenden.

Wenn Ihr Programm normal beendet wird, durch exit() oder durch die Rückkehr von main(), wird es automatisch öffnen und schließen alle offenen Streams und (unter den meisten Betriebssystemen) kostenlos zugewiesenen Speicher. Es empfiehlt sich jedoch, Ihre Ressourcen explizit zu bereinigen, bevor das Programm beendet wird, da dies normalerweise zu einem strukturierteren Programm führt. Manchmal der sauberste Weg, um Ihr Programm zu schreiben, ist nur zu beenden und die Bereinigung der Implementierung verlassen.

Aber seien Sie gewarnt, dass Sie sollten immer überprüfen Sie den Rückgabewert von fclose(). Eine Anekdote darüber, was passieren könnte, wenn Sie dies nicht tun, finden Sie unter "What are the reasons to check for error on close()?".

+1

Beachten Sie, dass der C-Standard * Implementierungen keinen freien Speicher benötigt. Tatsächlich ist ein häufiges Problem für die TI-89-Serie, dass C-Programme vor dem Beenden nicht aufgeräumt werden und das OS * nicht * aufräumt, so dass wiederholte Ausführungen eines undichten Programms den RAM auf dem Rechner erschöpfen würden. –