简体   繁体   中英

Segmentation Fault in Trie implementation in C

I'm trying to implement a trie data structure to spell-check a given text file. Currently, it seems to work for a couple words in the file, then it reaches a seg fault. I tried debugging to find the culprit, but all I found was that the value of "letter" is retaining seemingly random negative values (it should be between 1 and 27, inclusive). Normally the seg fault issue appears almost instantly after i start the program, so I'm not sure why the issue is popping up in the middle of the program.

    /**
     * Implements a dictionary's functionality.
     */

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

    #include "dictionary.h"


    //create global root node
    Trienode *root;
    //create word counter for size() function
    unsigned int wordcount = 0;

    //creates an empty node
    Trienode * newnode()
    {
        Trienode *nnode = NULL;
        nnode = (Trienode *)malloc(sizeof(Trienode));
        //initialize new node with null pointers and values
        nnode -> parent = NULL;
        for(int i = 0; i < 27; i++)
        {
            nnode -> children[i] = NULL;
        }
        return nnode;
    }

    void cleartrie(Trienode *head)
    {
        //if child node exists, free it, else continue with next iteration in for loop
        if(head)
        {
            for(int i = 0; i < 27; i++)
            {
                cleartrie(head -> children[i]);
            }
            free(head);
            head = NULL;
        }
    }

    /**
     * Returns true if word is in dictionary else false.
     */
    bool check(const char *word)
    {
        int i = 0;
        int letter;
        Trienode *head = root;

        while(word[i] != '\0')
        {
            if(isalpha(word[i]))
            {
                letter = word[i] - 'a';
            }
            else //it must be an apostrophe
            {
                letter = word[i] - 13;
            }
            if(!(head -> children[letter]))
            {
                return false;
            }
            else //a pointer must exist
            {
                head = head -> children[letter];
            }
            i++;
        }
        return true;
    }

    /**
     * Loads dictionary into memory. Returns true if successful else false.
     */
    bool load(const char *dictionary)
    {
        //open file
        FILE *infile = fopen(dictionary, "r");
        Trienode *parnode; //parent node
        root = newnode();
        Trienode *curnode = root; //current node

        int letter = 0;
        //while not end of file, read words
        while(fgetc(infile) != EOF)
        {
            //while not end of word, read letters
            for(;;)
            {
                int c;
                //read current letter in file
                c = fgetc(infile); 
                //convert input char to corresponding array location (a - z = 0-25, apostrophe = 26)
                if(isalpha(c))
                {
                    letter = c - 'a';
                }
                else if (c == '\'')
                {
                    letter = c - 13;
                }
                //if end of string, exit loop
                else if (c == '\0')
                {
                    //end of word, so endofstring = true
                    wordcount++;
                    break;
                }
                //move to next letter if not either apostrophe or alphabetical
                else
                {
                    break;
                }
                //if pointer to letter of word doesn't exist, create new node
                if(curnode -> children[letter] == NULL)
                {
                    curnode -> children[letter] = newnode();
                }
                //child node is the new current node
                parnode = curnode;
                curnode = curnode -> children[letter];
                curnode -> parent = parnode;

            }
            //return to root node
            curnode = root;
        } 

        fclose(infile);
        return true;
    }


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

    /**
     * Unloads dictionary from memory. Returns true if successful else false.
     */
    bool unload(void)
    {
        cleartrie(root);
        if (root == NULL)
        {
            return true;
        }
        return false;
    }

Sorry about the wall of text, but most of it is just there for context (I hope). The seg fault error is occurring on the if(!(head -> children[letter])) line of the check helper function.

Thanks in advance!

I suspect that your test file may contain some uppercase letters. If this is the case, then subtracting 'a' in an attempt to remap your letters will result in a negative number, since 'A' < 'a' . Have a look at the ASCII Table . Converting the letters to lowercase first should solve your problem.

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