2016-03-24 11 views
-1

Betrachten Sie dieses Programm:Eine andere Möglichkeit, in C aufzuräumen?

int main(void) 
{ 
    int* i = malloc(sizeof(int)); 
    int* j = malloc(sizeof(int)); 
} 

dies jedoch ist ein naiver Ansatz, weil malloc fehlschlagen und die Zeiger sind nicht free ‚d.

So können Sie dies tun:

int main(void) 
{ 
    int* i; 
    int* j; 

    if ((i = malloc(sizeof(int)) < 0) 
    { 
     return -1; 
    } 
    if ((j = malloc(sizeof(int)) < 0) 
    { 
     free(i); 
     return -1; 
    } 

    free(i); 
    free(j); 
} 

Jedoch habe ich diesen sehr fehleranfällig betrachten. Erwägen Sie, 20 Zeiger zuzuordnen, im letzten malloc Fehlerfall müssen Sie free 19 Variablen und dann return -1.

Ich weiß auch, atexit, was mir, es zu schreiben, wie dies helfen kann:

int* i; 
int* j; 

void del_i(void) 
{ 
    free(i); 
} 

void del_j(void) 
{ 
    free(j); 
} 

int main(void) 
{ 
    if ((i = malloc(sizeof(int)) < 0) 
    { 
     return -1; 
    } 
    else 
    { 
     atexit(del_i); 
    } 

    if ((j = malloc(sizeof(int)) < 0) 
    { 
     return -1; 
    } 
    else 
    { 
     atexit(del_j); 
    } 
} 

Was ist besser, aber ich mag nicht mit allen Zeigern als global zu erklären. Gibt es eine Möglichkeit, diese beiden Ansätze zu kombinieren, im Grunde:

  1. Mit Destruktoren für Zeiger, die entweder direkt ausgeführt werden kann oder mit atexit verwendet werden.
  2. Zeiger auf lokale Funktionen haben.
+0

ich nicht bekommen Ihr Punkt. Wenn Sie die Ausführung des Programms beenden/stoppen, warum sollten Sie sich dann über 'free()' Gedanken machen? –

+0

1. Sie sollten immer "frei" Zeiger. 2. Betrachten Sie dies im Zusammenhang mit einem größeren Programm – hgiesel

+0

Danke für die Aufklärung, aber ich bleibe bei meiner Version. :) –

Antwort

0
int main(void) 
{ 
int* i = NULL; // Init with NULL otherwise free on none NULL possible 
int* j = NULLL; 

if (!(i = malloc(sizeof(int))) 
{ 
    goto exit; 
} 
if (!(j = malloc(sizeof(int))) 
{ 
    goto exit; 
} 
... 
exit: 
    free(i); 
    free(j); 
    ... 
    return err; 
} 

Dies ist etwas, das Sie mit GOTO-Anweisungen lösen können.

+2

Sie springen zu "exit", wenn die Zuordnungen erfolgreich sind. Nicht so hilfreich. – unwind

+0

Ja, du hast recht meinen Tresor repariert, vergaß den! – Schafwolle

+1

Seien Sie vorsichtig bei http://www.dwheeler.com/essays/apple-goto-fail.html -Typ Fehler. – Tommy

3

Zuerst wird dies nichtmalloc Fehler feststellen:

if ((i = malloc(sizeof(int)) < 0) 
{ 
    return -1; 
} 

malloc kehrt NULL auf Versagen, keine negative Zahl.

Zweitens, atexit ist gut für die Bereinigung von statischen und globalen Objekten. Es ist keine gute Idee, lokale Objekte global zu machen, nur um sie innerhalb von atexit zu verwenden.

Ein besserer Ansatz besteht darin, einen struct für alle verwandten Zeiger, die Sie in einer Alles-oder-Nichts-Einheit zuordnen müssen, zu definieren, eine Funktion für die Freigabe aller auf einmal zu definieren und eine Funktion zu schreiben, die sie einzeln zuweist mit Speicher auf jeder Zuweisung Überprüfung:

typedef struct AllOrNothing { 
    double *dPtr; 
    int *iPtr; 
    float *fPtr; 
    size_t n; 
} AllOrNothing; 

void freeAllOrNothing(AllOrNothing *ptr) { 
    free(ptr->dPtr); 
    free(ptr->iPtr); 
    free(ptr->fPtr); 
    free(ptr); 
} 

int allocateAllOrNothing(size_t n, AllOrNothing **res) { 
    *res = malloc(sizeof(AllOrNothing)); 
    if (*res == NULL) { 
     return -1; 
    } 
    // Freeing NULL is allowed by the standard. 
    // Set all pointers to NULL upfront, so we can free them 
    // regardless of the stage at which the allocation fails 
    (*res)->dPtr = NULL; 
    (*res)->iPtr = NULL; 
    (*res)->fPtr = NULL; 
    (*res)->n = n; 
    (*res)->dPtr = malloc(n*sizeof(double)); 
    if ((*res)->dPtr == NULL) { 
     free(*res); 
     *res = NULL; 
     return -1; 
    } 
    (*res)->fPtr = malloc(n*sizeof(float)); 
    if ((*res)->fPtr == NULL) { 
     free(*res); 
     *res = NULL; 
     return -1; 
    } 
    (*res)->iPtr = malloc(n*sizeof(int)); 
    if ((*res)->iPtr == NULL) { 
     free(*res); 
     *res = NULL; 
     return -1; 
    } 
    return 0; 
} 
4

free auf NULL ist definiert als ein sicherer no-op zu sein. So eine Nicht-Springen Variante könnte sein:

int *i = malloc(sizeof(int)); 
int *j = malloc(sizeof(int)); 

if(i && j) 
{ 
    // do some work 
} 

free(i); 
free(j); 
0
int main(void) 
{ 
    int* i = NULL; 
    int* j = NULL; 
    bool success = false; 

    do { 
     i = malloc(sizeof(int)); 
     if (NULL == i) break; 

     j = malloc(sizeof(int)); 
     if (NULL == j) break; 

     success = true; 
    } while (0); 

    if (!success) 
    { 
     printf("Something failed!"); 
    } 
    else 
    { 
     printf("All succeeded!"); 
     // Do more work 
    } 

    free(i); 
    free(j); 
    return (success? 0 : 1); 
} 
-1
int *i=NULL,*j=NULL; 

    if(!(i=malloc(sizeof(int)))) 
      goto EXIT; 
    if(!(j=malloc(sizeof(int)))) 
      goto EXIT; 
    /* do some work */ 
    return 0; 
    EXIT: 
      free(i); 
      free(j); 
      exit(EXIT_FAILURE); 

Obwohl goto gilt als schlechter Programmier aber hier können wir es nutzen unsere Aufgabe mit Leichtigkeit und Einfachheit zu erledigen

0

Vermeiden Sie mehrere Ausstiegspunkte. Vermeiden Sie Interlacing-Zuweisung und Fehlerbehandlung. Folgt einer sauberen Reihenfolge der Operation:

  1. Deklarieren, Zuweisen und Initialisieren von Ressourcen ..
  2. Wenn alles erfolgreich ist, tun Sie die Aufgabe.
  3. Aufräumen.
  4. Rückgabestatus.

// Do all allocations first, test their `NULL`-ness, then free them all. 
int main(void) { 
    // Allocate resources 
    // declare and allocate in one step 
    int* i = malloc(sizeof *i); 
    double* j = malloc(sizeof *j); 

    // Test for acceptability 
    bool ok = i && j; 

    // Perform the main body of code 
    if (ok) { 
     ; // do normal process in the code; 
    } 

    // free resources 
    free(i); 
    free(j); 

    // return status 
    return ok ? 0 : -1; 
}