Search code examples
cpointersstructmemory-leaks

C - How to free a double void pointer that has an array of dynamic structs assigned to it with malloc


My C looks like this.

typedef struct thing
{
    void *fooStruct;
} thing;

typedef struct foo
{
    int *somethingNumber;
    char something;
} foo;

extern void **double_ptr;
void *ptr;

int main() {
    ptr = (struct thing*)malloc(sizeof(thing) * 5);
    double_ptr = &ptr;

    for (int i = 0; i<5 ; i++) {
        ((struct thing *)*double_ptr)[i].fooStruct = (struct foo*)malloc(sizeof(foo));
    }

    // <Things I've tried to free the memory>

    return 0;
}

I've tried a few of things so I can free all of the memory I malloc'd throughout the program (all of the dynamic 'foo' structs, all of the dynamic 'thing' structs, 'ptr', and 'double_ptr'), but I keep running into errors. Tried searching here but I haven't found anything that has helped me.

Some of the attempts I remember so far:

// Attempt 1:
free(double_ptr);

// Attempt 2:
for (int i = 0; i < 5; i++) { 
    aux_ptr = &((struct thing*)*double_ptr)[i]; 
    free(aux_ptr);
}

free(double_ptr);

// Attempt 3:
void *aux_ptr;

for (int i = 0; i < 5; i++) { 
    aux_ptr = ((struct thing*)*double_ptr)[i].fooStruct; 
    free(aux_ptr);
    aux_ptr = &((struct thing*)*double_ptr)[i]; 
    free(aux_ptr);
}

free(*double_ptr);

// Attempt 4:
void *aux_ptr;

for (int i = 0; i < 5; i++) { 
    aux_ptr = ((struct thing*)*double_ptr)[i].fooStruct; 
    free(aux_ptr);
    aux_ptr = &((struct thing*)*double_ptr)[i]; 
    free(aux_ptr);
}

free(double_ptr);

I expected to have no memory leaks (or for the code to compile and run at all), but these various attempts don't fully work. Attempt 1 and 4 don't even compile (invalid pointer), while Attempt 2 and 3 have memory leaks.

Pointers have always been an issue for me, so I'm sorry if the solution is easier than I think. I'd REALLY appreciate some help :c


Solution

  • For each call to malloc, there should be a corresponding call to free.

    Looking at the allocation code:

    ptr = (struct thing*)malloc(sizeof(thing) * 5);
    double_ptr = &ptr;
    
    for (int i = 0; i<5 ; i++) {
        ((struct thing *)*double_ptr)[i].fooStruct = (struct foo*)malloc(sizeof(foo));
    }
    

    You have a single malloc for an array stored in ptr, then a single malloc in a loop run 5 times for the fooStruct member of a struct thing. So you want to free exactly that in the reverse order.

    Attempt 3 is the closest. You're calling free twice in the loop, but you only called malloc once in the initial loop. Specifically, &((struct thing*)*double_ptr)[i] doesn't point to allocated memory, so get rid of that.

    void *aux_ptr;
    
    for (int i = 0; i < 5; i++) { 
        aux_ptr = ((struct thing*)*double_ptr)[i].fooStruct; 
        free(aux_ptr);
    }
    
    free(*double_ptr);