Cleanup

From C

Jump to: navigation, search

One of the common uses for goto statements is to do cleanups. By using goto statements with structured labels we avoid excessive indentations, and we avoid using sentinel values or flags to indicate which resources need to be cleaned up.

Code Sample #1

The following code sample demonstrates cleaning up by using goto statements, with no explicit error codes.

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

struct s {
    void *buffer;
    size_t len;
    FILE *fp;
};

int func(struct s **pp, size_t size) {
    *pp = malloc(sizeof **pp);
    if (*pp == NULL)
        goto error1;
    
    (*pp)->buffer = malloc(size);
    if ((*pp)->buffer == NULL)
        goto error2;
    
    (*pp)->fp = fopen("test.txt", "r");
    if ((*pp)->fp == NULL)
        goto error3;
    
    
    /* do something */
    
    
    return 0;
    
    error3:
    free((*pp)->buffer);
    
    error2:
    free(*pp);
    
    error1:
    return -1;
}

int main(void) {
    int r;
    struct s *p;
    
    r = func(&p, 100);
    if (r != 0) {
        puts("Error: func();");
        return r;
    }
    
    /* do something */
    
    if (fclose(p->fp) != 0)
        r = -1;
    
    free(p->buffer);
    free(p);
    
    return r;
}

Code Sample #2

The following code sample demonstrates cleaning up by using goto statements, with explicit error codes.

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

enum error_codes {
    SUCCESS,
    MALLOC1,
    MALLOC2,
    FOPEN,
    FCLOSE
};

char *errors[] = {
    [SUCCESS] = "SUCCESS",
    [MALLOC1] = "MALLOC1",
    [MALLOC2] = "MALLOC2",
    [FOPEN] = "FOPEN",
    [FCLOSE] = "FCLOSE"
};

struct s {
    void *buffer;
    size_t len;
    FILE *fp;
};

int func(struct s **pp, size_t size) {
    int r;
    
    *pp = malloc(sizeof **pp);
    if (*pp == NULL) {
        r = MALLOC1;
        goto error1;
    }
    
    (*pp)->buffer = malloc(size);
    if ((*pp)->buffer == NULL) {
        r = MALLOC2;
        goto error2;
    }
    
    (*pp)->fp = fopen("test.txt", "r");
    if ((*pp)->fp == NULL) {
        r = FOPEN;
        goto error3;
    }
    
    
    /* do something */
    
    
    return SUCCESS;
    
    error3:
    free((*pp)->buffer);
    
    error2:
    free(*pp);
    
    error1:
    return r;
}

int main(void) {
    int r;
    struct s *p;
    
    r = func(&p, 100);
    if (r != SUCCESS) {
        printf("Error: %s\n", errors[r]);
        return r;
    }
    
    printf("%s\n", errors[r]);
    
    if (fclose(p->fp) != 0)
        r = FCLOSE;
    
    free(p->buffer);
    free(p);
    
    return r;
}

.

Personal tools