0

I've implemented check() and load() using tries. I have a pointer 'head' to the top of the dictionary trie (NB it's called root in the walkthrough) that I need to pass from load() to check() I declared head as extern in dictionary.h and initialised at the top level in dictionary.c and inside of load()

The code compiles OK but I get a seg fault. On inspection, it comes from the fact that when load() is done and check() starts running, head becomes empty despite my efforts to make it global and accessible to all functions I know I am losing memory (thanks Valgrind) when head disappears once load() is finished, but no idea how to fix this...

How can I make sure check() has access to my pointer created by load()?

Thank you Victor

here are the code snippets: dictionary.h - declared head as extern

/**
 * dictionary.h
 *
 * Computer Science 50
 * Problem Set 5
 *
 * Declares a dictionary's functionality.
 */

#ifndef DICTIONARY_H
#define DICTIONARY_H

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

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

    }
    node;


extern int num_words;
extern node* head;
extern node* root;

dictionary.c - initialised head at the topp and in load(); check() uses head too

/**
 * dictionary.c
 *
 * Computer Science 50
 * Problem Set 5
 *
 * Implements a dictionary's functionality.
 */

#include <stdbool.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdio.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <string.h>
#include "dictionary.h"

int num_words;
node* head;
node* root;

bool load(const char* dictionary)
{
    // TODO
    FILE* dc = fopen(dictionary, "r");
    node* head = malloc(sizeof(node));
    //node* head = malloc(sizeof(node));
    if (dc == NULL)
    {
        printf("Could not open dictionary %s.\n", dictionary);
        num_words = 0;
        return 2;
    }

    char word[LENGTH+1] = ""; //does this not waste memory?
    int z = 0; //word counter
    for (int w = fscanf(dc, "%s", word); w != EOF; w = fscanf(dc, "%s", word))
    {
        root = head;
        z = z+1;
        for(int i = 0; i < LENGTH +1; i++)
        {

            int x = (int)word[i];//ascii value

            if(x == 0)
            {
                root->is_word = 1;
                i = LENGTH +1;
            }

            else
            {
                if(x == 39)
                {
                    x = 26;
                }
                else if( x>= 65 && x<=90)
                {
                    x = x-65;
                }
                else if(x>= 97 && x<=122)
                {
                    x = x-97;
                }

                if(root->children[x] == NULL)
                {
                    node* newnode = malloc(sizeof(node));
                    root->children[x] = newnode;
                }
                root = root->children[x];
            }
        }
        memset(&word[0], 0, sizeof(word));

    }


    num_words = z;
    return true;

    //return false;
}


bool check(const char* word)
{
    // TODO
    int len = strlen(word);
    root = head; //THIS DOES NOT PASS ON THE VALUES

    for(int i=0; i < len; i++)
    {
        int x = (int)word[i];//ascii value
        if(x == 39)
        {
            x = 26;
        }
        else if( x>= 65 && x<=90)
        {
            x = x-65;
        }
        else if(x>= 97 && x<=122)
        {
            x = x-97;
        }

        if((i==len-1 && root->is_word ==0) || (i<len-1 && root->children[x] == NULL))
        {
            //printf("negative at symbol %i\n",i); //// START THINKING HERE
            //x seems t be picking up the right character but there is nothig in root.children[x]
            //printf("reason: %i letter: %c, x: %i\n",root->children[x] == NULL, word[i], x);
            return false;

        }
        else if(i==len-1 && root->is_word ==1)
        {
            printf("found word at symbol %i\n",i);
            return true;

        }
        else if(i<len-1)
        {
            printf("next at symbol %i\n",i);
            root = root->children[x];
        }
    }
    return false;
}
0

The problem lies in load(). The code declares head as a local var inside of load.

node* head = malloc(sizeof(node));

This is called creating a shadow variable - a local var that masks another var with greater scope like a global var. The local shadow supercedes the earlier var with the same name and the original var is hidden. When the shadow goes out of scope, the original var becomes visible again. In this case, the code is creating the entire trie based on the local shadow var head. When load ends, the local shadow var ceases to exist and the global head, which contains garbage data (it wasn't initialized with an address or NULL) is used by check. Even if it was NULL, it would still seg fault because it would try to access a nonexistent element.

Drop the node* from the above statement. Of course, there are more problems to follow, but those would be new questions. ;-)

As for using extern, its the same with or without this keyword. You could declare these vars as globals in dictionary.c and they will work fine across the file. The extern keyword would only be needed if the var were needed across multiple source files. Here's a nice explanation of extern: http://www.geeksforgeeks.org/understanding-extern-keyword-in-c/

If this answers your question, please click on the check mark to accept. Let's keep up on forum maintenance. ;-)

You must log in to answer this question.

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