简体   繁体   中英

C trie node reassignment causing segmentation fault

I am trying to implement a spellchecker, and one step is to load a dictionary into a trie structure. I have used GDB to determine that, from my understanding, I am getting a segmentation fault every time I try to assign current->children to a value. Full code at the bottom, but the method in question:

bool load(const char* dictionary)
{
    FILE* dic = fopen(dictionary, "r");

    if(dic == false)
    {
        return false;
    }

    root = calloc(27, sizeof(node));
    node* current = NULL;
    /**for(int i=0;i<27;i++)
    {
        current->children[i]=NULL;
    }*/ //this will be the location of the segmentation fault if uncommented
    int a = 0;

    while((a = fgetc(dic)) != EOF)
    {
        if (a == '\n')
        {
            //this is the end of a word
            if(!current->is_word)
            {
                //duplicate case
                current->is_word = true;
                wordcounter++;
            }
            current = root;        
        }
        else
        {
            if(current->children[a-'a'] == NULL)
            {
                current->children[a-'a'] = calloc(27,sizeof(node));
            }
            current = current->children[a-'a'];
        }
    }
    if(current!= root && !current->is_word)
    {
        current->is_word = true;
        wordcounter++;
    }

    fclose(dic);
    return true;
}

There is commented code there that I tried to implement after checking a couple other answers on stackoverflow, but that just causes the segmentation fault to occur at that for loop. Otherwise, it occurs at the if(current->children[a-'a']==NULL){...}

What's happening here? I thought calloc() automatically set the assigned memory to 0? What memory am I touching that I'm not supposed to?

Full .c below:

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

#include "dictionary.h"

typedef struct node
{
    bool is_word;
    struct node* children[27];
}
node;

node* root;
int wordcounter=0; 

 //Returns true if word is in dictionary else false.

bool check(const char* word)
{
    node* current = root;
    int b = 0;

    while(word[b] != '\n')
    {
        int letter = tolower(word[b]);

        if(letter == '\'')
        {
            return false;
        }

        if(current->children[letter-'a'] != NULL)
        {
            current = current->children[letter-'a'];
            b++;
        }
        else
        {
            return false;
        }
    }

    if(current->is_word == true)
    {
        return true;
    }   
    return false;
}


 // Loads dictionary into memory.  Returns true if successful else false.
bool load(const char* dictionary)
{
    FILE* dic = fopen(dictionary, "r");

    if(dic == false)
    {
        return false;
    }


    root = calloc(27, sizeof(node));
    node* current = NULL;
    /**for(int i=0;i<27;i++)
    {
        current->children[i]=NULL;
    }*/
    int a = 0;

    while((a = fgetc(dic)) != EOF)
    {
        if (a == '\n')
        {
            //this is the end of a word
            if(!current->is_word)
            {
                //duplicate case
                current->is_word = true;
                wordcounter++;
            }
            current = root;        
        }
        else
        {
            if(current->children[a-'a'] == NULL)
            {
                current->children[a-'a'] = calloc(27,sizeof(node));
            }
            current = current->children[a-'a'];
        }
    }
    if(current!= root && !current->is_word)
    {
        current->is_word = true;
        wordcounter++;
    }

    fclose(dic);
    return true;
}


//Returns number of words in dictionary if loaded else 0 if not yet loaded. 
unsigned int size(void)
{
    return wordcounter;
}


 //Unloads dictionary from memory.  Returns true if successful else false. 
void memFree(node* current)
{
    for(int i = 0; i < 27; i++)
    {
        if(current->children[i] !=NULL)
        {
            memFree(current->children[i]);
        }
    }
    free(current);
}

bool unload(void)
{
    memFree(root);    
    return true;
}

The error happens because you're initializing current = NULL , then dereferencing it ( current->children ). It's a straight up null pointer dereference.

Looking at the rest of the code, you probably meant to do

node *current = root;

instead.

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