简体   繁体   中英

Freeing a tree structure in C

I'm using a tree of structs in my C program, where the struct is set up like so:

typedef struct SymbolTable_t
{
    int id;

    Symbol symbols[size];
    int count;
    struct SymbolTable_t * parent;

    int scopeCount;
    struct SymbolTable_t * childScopes[size];

    int isM;
} SymbolTable;

And when I create a new SymbolTable I allocate memory for the child scopes like this:

SymbolTable *t = malloc(sizeof(*t));
// other stuff ...
for(int i = 0; i < size; i++)
{
   childScopes[i] = malloc(sizeof(SymbolTable)); // <---- line 41
}

And at the end of my program when I want to free the memory allocated to them I wrote a recursive function:

void freeSymbolTables(SymbolTable* root)
{
    if(root == NULL) return;
    for(int i = 0; i < size; i++)
    {
        freeSymbolTables(root->childScopes[i]);
    }
    free(root);
}

Note that I don't really use entirety of childScopes, so only some of them will actually point to something by the end of the program. I thought this was fine but running in valgrind it tells me a significant amount of memory is 'definitely lost' at line 41, which I think means the pointers are going out of scope without a call to free at the end of the program lifetime. I'm unsure what's going wrong here since I think this should free all the memory.

Minimal reproducible example

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

#define s_size 40

typedef struct SymbolTable_t
{
    struct SymbolTable_t * s[s_size];
    int count;
} SymbolTable;

SymbolTable* createSymbolTable()
{
    SymbolTable* t = malloc(sizeof *t);
    t->count = 0;
    for(int i = 0; i < s_size; i++)
    {
        t->s[i] = malloc(sizeof t->s[i]);
    }
    return t;
}

void freeSymbolTable(SymbolTable* root)
{
    if(root == NULL) return;
    for(int i = 0; i < root->count; i++) freeSymbolTable(root->s[i]);
    for(int i = root->count; i < s_size; i++) free(root->s[i]);
    free(root);
}

void addChildScope(SymbolTable* parent, SymbolTable* child)
{
    parent->s[parent->count++] = child;
}

int main()
{
    SymbolTable *t =  createSymbolTable();
    SymbolTable *c = createSymbolTable();
    addChildScope(t, c);
    freeSymbolTable(t);
    return 0;
}

When I run this, valgrind tells me 8 bytes are definitely lost, even thought I think that my function should free all the memory.

You are basically doing:

// in createSymbolTable()
   t->s[0] = malloc(...);

and then:

// in addChildScope()
     parent->s[0] = child;      // malloc(...) from above is just lost...

You could "patch"/workaround it with:

void addChildScope(SymbolTable* parent, SymbolTable* child) {
    free(parent->s[parent->count]);
    parent->s[parent->count++] = child;
}

But overall I see no point in mallocing anything in createSymbolTable if the memory is never used anyway. Just don't malloc it in createSymbolTable anyway, the memory is not used.

Also, theoretically (but it's never used, so it does not matter) the line:

t->s[i] = malloc(sizeof t->s[i]);

is suspicious - it's meant to be:

t->s[i] = malloc(sizeof *t->s[i]);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM