Search code examples
cfreefcloseatexit

Exists a way to free memory in atexit or similar without using global variables?


I am developing a project in C, and I need to free the allocated memory and also close all the open files before it exits.

I decided to implement a clean function that will do all this stuff and call it with atexit because there are a lot of possible exit scenarios.

The problem is that atexit doesn't allow me to set functions with parameters, so I can't send to clean the pointers that need to be freed in the end of the process.

So I need to declare as global variables every pointer that may need to be freed, and every file that may remaining open in the program? (I already did that but doesn't looks good) or does exist a similar function to atexit that allows to send parameters? or more probably there is another way that I am missing?


Solution

  • Using a static pointer inside a function:

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

    Another method using a single global variable: you can store all objects to be freed in an array of pointers or a linked list, this example uses realloc (doesn't check (m/re)alloc for brevity):

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