Search code examples
ctrie

Cleaning double linked list Trie structure in c


I want to prevent memory leaks, so i want to free the trie. below you can see my attempt at freeing the memory that was used.

// to see how many words are cleaned up.
static int teller_cleanup = 0;

struct ac {
    int value;
    char character; 
    char * word;
    struct ac *next;
    struct ac *previous;
    struct ac *child;
    struct ac *parent;
};

it is a double or 4 way linked list not sure what i am suposed to cal it.

void cleaner(struct ac* a) {
    ac * temp = NULL;
    if (a != NULL) {
        if (a -> child == NULL && a -> next == NULL) {
            teller_cleanup ++;
            if (a -> parent != NULL) {
                temp = a -> parent;
            }
            else {
                temp = a -> previous;
             }
             free(a -> word);
             free(a);
             a = temp;
        }
        if (a -> child != NULL) {
            cleaner(a -> child);
        }
        if (a -> next != NULL) {
            cleaner(a -> next);
        }
     }
 }

int cleanup(struct ac* a) {
    // means that it is in the root
    // therfore it needs to go to the first node.
    if (a -> next == NULL && a -> parent == NULL) {
        a = a -> child;
    }
    cleaner(a);
    return teller_cleanup;
}

But it seems that it is not working properly. it gives a error:

double free or corruption (fasttop): 0x0000000000fffa70 ***

what i don't seem to get, because when 'child' and 'next' are both 'NULL' than 'a' is the outher most node. And i believe only one of the recusive if statements can go to one of these outher most nodes.

i will try to visualize the trie:

[root]
   |
  \/
[h] -- > [b]
 |        |
\/       \/
[i]      [y] --> [e] 

so the trie contains the words hi, by and be. root points to first character of first word and all the arrows are double linked. from 'h' to 'b' is next and from 'h' to 'i' is child.

Can someone maybe see what i am doing wrong? It would be much appreciated.


Solution

  • I think you're making it too complicated by checking for NULL in several places. When you have multiple recursion, it's easier to check for NULL after entering the function, rather than before calling it.

    In addition, you can avoid the global teller_cleanup variable if you pass a local variable by pointer to cleaner().

    void cleaner(struct ac *a, int *teller_cleanup) 
    {
        if (a != NULL) {
            cleaner(a->next, teller_cleanup);
            cleaner(a->child, teller_cleanup);
            free(a->word);
            free(a);
            (*teller_cleanup)++;
        }
    }
    
    int cleanup(struct ac *a)
    {
        int teller_cleanup = 0;
        cleaner(a, &teller_cleanup);
        return teller_cleanup;
    }