0

After completing load, I'm working on the check function. My implementation compiles but leads to a segmentation fault with various dictionaries and text files. My load function works, and the program prints MISSPELLED WORDS right before crashing.

GDB indicates that the problem occurs at the first line where my traversal pointer checks if the node found at the index value is NULL.

      if (trav->children[index] == NULL)

Is there an issue with scope between my load and check functions? What else could be causing the segmentation fault?

Here is my code:

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

node* root = NULL;
node* trav = NULL;



bool check(const char* word)
{
    // initialize variable
    node* trav = root;
    unsigned int index = 0;

// loop through chars in array
for (int i = 0; i < strlen(word); i++) // n = strlen
{
    if (isalpha(word[i]))
    {
        index = tolower(word[i]) - 'a';
    }
    else if (word[i] == '/')
    {
        index = 26;
    }

    // check child element 
    if (trav->children[index] == NULL)
    {
        return false;
    }
    else if (trav->children[index] != NULL && i != strlen(word) - 1)
    {
        trav = trav->children[index];
    }

    else if (i == strlen(word) - 1)
    {
        return trav->is_word;
    }
}
return false;
}


bool load(const char* dictionary)
{
// open input file 
FILE* dicptr = fopen(dictionary, "r");
if (dicptr == NULL)
{
    printf("Could not open %s.\n", dictionary);
    return false;
}

// create root, initiate childrem to NULL 
node* root = (struct node*)calloc(1, sizeof(node));
node* trav = root;

//iterate throught trie
unsigned int index = 0;
for (unsigned int c = fgetc(dicptr); c != EOF; c = fgetc(dicptr))
{
    if (c == '\n')
    {
        trav->is_word = true;
        trav = root;
        index = 0;
    }
    else if (isalpha(c))
    {
        tolower(c);
        index = c - 'a';

        if (trav->children[index] == NULL)
        {
            trav->children[index] = (struct node*)calloc(1, sizeof(node));
            trav = trav->children[index];
        }
        else if (trav->children[index] != NULL)
        {
            trav = trav->children[index];
        }
    }
    else if (c == '/' && index > 0)
    {
        index = 26;
        if (trav->children[index] == NULL)
        {
            trav->children[index] = (struct node*)calloc(1, sizeof(node));
            trav = trav->children[index];
        }
        else if (trav->children[index] != NULL)
        {
            trav = trav->children[index];
        }
    }

}
fclose(dicptr);
return true;
}

2 Answers 2

2

OK, after careful debugging I have discovered and fixed the issue. It doesn't have to do with malloc/calloc. Even though my forward declaration of the struct/root node was properly placed outside of any function, ie globally, in the load function, I was writing

struct node* root = malloc(.......)

instead of

root = malloc(.....)

This erased the global scope of the variable, and reassigned root as a local variable. When check ran, it seg faulted the instant trav (set equal to root) was called, because it had already been dropped after load was done.

2
  • 1
    You are my hero. Had the same problem, drove me up the walls. Dec 2, 2016 at 10:10
  • 1
    Thanks so much for this. Had the same problem, and this resolved it!
    – user14554
    Dec 29, 2016 at 17:04
0

I think your problem is coming from calloc. calloc sets allocated memory to zero, meaning you can't check for Null. Also, ur first else if in check is missing one of the quotes and, u used a forward slash instead of a back slash... good luck

7
  • I'm not sure I agree. From what I understand, 0 and NULL are equivalent as far as C is concerned. I check for NULL using calloc in the load function - it works there as it should without leading to a segmentation fault. The value wouldn't be NULL anyway. Since I've called load on the large dictionary at the point when check begins to run, all of trav->children should be allocated, because the dictionary definitely has a word that starts with every letter in the alphabet. Jun 15, 2016 at 11:51
  • Hey, I'm gonna have to insist coz when i replaced just your check function with my already working PSet, making those adjustments did the Trick. personally, I would malloc and then set all the addresses to null because trust me null and zero are way different
    – karuhanga
    Jun 15, 2016 at 14:41
  • Ok I'll give it a try and let you know. I appreciate your looking into it Jun 15, 2016 at 19:42
  • I've switched all the callocs to malloc appropriately and am still experiencing the same issue. After debugging more carefully with GDB, i see that load works properly, but when check is called, the traversal pointer does not get re-pointed at root, leading to the seg fault the first time it is accessed. root seems to disappear when check is called. This is leading me to believe that I am dealing with a scope issue identical to the one discussed here: reddit.com/r/cs50/comments/40uck7/pset5_check_segfault How did you declare your pointers? Jun 18, 2016 at 18:37
  • hey after mallocing, immediately set that memory to null, so you can use that null checking later. otherwise, it won't be null in that memory... thought I mentioned it... trust me
    – karuhanga
    Jun 19, 2016 at 11:15

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .