Search code examples
cpointerssegmentation-faultfreesingly-linked-list

Segfault freeing memory - only when there are too many allocated


Im trying to read words from a file (formated with only one word per line) into a singly linked list. The code below works fine with small files. Once I start adding a lot of lines to the file to be read, I start getting segfault errors.

The line that gives the segfault is this one: free(a->word) from the destroy() function. Again, two things Id like to point out:

1) The code works fine if I don't call the destroy() function no matter how big the file is;

2) The code also works fine if I call the destroy() function and the word file is small (less than 100k lines).

I'm lost to what could be causing this behavior. Any ideas? Thanks!

 typedef struct dictionary_entry
{
    char *word;
    struct dictionary_entry *next;
}
dictionary_entry;

dictionary_entry *head;
int LENGTH = 50;

int destroy(dictionary_entry *a)
{
    if (a == NULL)
    {
        free(a);
    }

    else
    {
        destroy(a->next);
        free(a->word);
        free(a);
    }

    return 0;
}

void push(char *a)
{
    dictionary_entry *new_data = malloc(sizeof(dictionary_entry));
    new_data->word = a;
    new_data->next = head;
    head = new_data;
}

int main(void)
{
    head = NULL;

    char dictionary_word[LENGTH + 2]; //extra chars for the \0 and \n

    char *added_word = NULL;

    FILE *file = fopen("./victor", "r");

    if (file == NULL)
    {
        return 1;
    }

    while (fgets(dictionary_word, LENGTH + 1, file) != NULL)
    {
        added_word = malloc((LENGTH + 2) * sizeof(char));
        strcpy(added_word, dictionary_word);
        push(added_word);
    }

    fclose(file);

    if (destroy(head) == 0)
    {
        return 0;
    }

    else
    {
        return 1;
    }
}    

Solution

  • If the linked list is too large, the stack will probably overflow from your recursive calls. Try an iterative approach instead:

    int destroy(dictionary_entry *a)
    {
        while(a)
        {
            dictionary_entry *next = a->next;
    
            free(a->word);
            free(a);
    
            a = next;
        }
    
        return 0;
    }