2

First post, extremely limited in coding knowledge and new to C. Be gentle! I am at the point where "trying" different things is just confusing me more and more. I need someone's correct guidance!

This particular problem is from an online edX course I am attempting which ultimately when implemented correctly, checks a given word read in from a text file (the 'check' function) and compares it to each word read into (from the 'load' function) a linked list of structs.

I believe I have the load function implemented correctly as when I use gdb, as I am seeing what I anticipate as I step through it, but my question and my problem relates specifically to the check function. I still have a lot to implement to finish my code but while testing with gdb, I am not seeing values of the char* member of the struct correspond with what I anticipate I should see.

  1. When using gdb and stepping through the 'check' function and trying to access the dword member of the struct nodes in the linked list I created in the load function, I anticipate I should see a string for the char* member. For instance, I anticipate the word "cat" assigned to current->dword , but am instead seeing in gdb when I test:

    ~(gdb) print current->dword

    $13 = 0xbfffede2 "\004\b\214\365\372D\300\355\377\277"

My thoughts are that I'm still only accessing an address somehow and not the actual value, but I'm oblivious as to why this is. When the node is created in the load function, a value is assigned to the dword member correctly (at least as far as I can tell while stepping through the code in gdb) but doesn't seem to be accessed correctly in the check function. Any help for a newbie would be appreciated!

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

    #include "dictionary.h"

    typedef struct node
    {
        char* dword;
        struct node* next;
    }
    node;

    // keep track of #of words in dictionary loaded
    int wordCounter = 0;

    // create root for hash table
    node* root[26];

    // create cursor to keep place in creating, pointing, and traversing through nodes
    node* current = NULL;

    /**
     * Returns true if word is in dictionary else false.
     */
    bool check(const char* word)
    {
        // size of word read into buffer
        int wordSize = sizeof(word);

        // prepare to make a new lowercase only word for comparison to lowercase only dictionary
        char bufWord[wordSize];

        // make it
        for(int i = 0; i < wordSize; i++)
        {   
            if (i == wordSize - 1)
            {
                bufWord[i] = '\0';
            }

            else
            {
                bufWord[i] = tolower(word[i]);
            }
        }

        // hash word to achieve proper root node location
        int hash = bufWord[0] - 97;

        // point to the correct root node to begin traversing
        current = root[hash];

        // make sure there is even a word in hash table location
        if(root[hash] == NULL)
        {
            return false;
        }

        else if(root[hash] != NULL)
        {
            // progress through the nodes until the last node's next pointer member is NULL
            while(current != NULL)
            {
                // compare 1st letter only of current->dword[i] to bufWord[i] to save time

                    // if they don't match, return false

                    // if they do match then continue
    \
                char dictWord[wordSize];

                // hold copy of struct member value to compare to dictWord
                char* wordTemp = current->dword;

                // 
                for(int i = 0; i < wordSize; i++)
                {   
                    dictWord[i] = wordTemp[i];
                }

                // do a spell check
                if(strcmp(bufWord, dictWord) == 0)
                {
                    return true;
                }

                else
                {
                    // set current to the next node if any or NULL if it's already the last node in the list
                    current = current->next;
                }
            }    
        }

        return false;
    }

    /**
     * Loads dictionary into memory.  Returns true if successful else false.
     */
    bool load(const char* dictionary)
    {   
        // buffer for reading in dictionary words
        char wordIn[LENGTH + 1];

        // open the dictionary file
        FILE* newDict = fopen(dictionary, "r");

        for (int i = 0; i < 27; i++)
        {
            root[i] = NULL;
        }

        // while there are words to read
        while(fscanf(newDict, "%s ", wordIn) > 0)
        {

            // keep track of #of words for constant time read in size function
            wordCounter++;

            // hash the first letter for the location in root
            int hash = wordIn[0] - 97;

            // malloc space for a new node
            node* newNode = malloc(sizeof(node));

            // error check
            if (newNode == NULL)
            {
                return false;
            }

            // set value member of node to current word
            newNode->dword = wordIn;

            // first insertion into linked list if that root node has not been used yet 
            if(root[hash] == NULL)
            {
                // sets to NULL
                newNode->next = root[hash];

                // link it
                root[hash] = newNode;
            }

            else if(root[hash] != NULL)
            {
                // starts at the root
                node* current = root[hash];

                // insert into new beginning of list
                newNode->next = current;
                root[hash] = newNode;
            }
        }

        fclose(newDict);
        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.
     */
    bool unload(void)
    {
        // TODO
        return false;
    }

1 Answer 1

1

The source of your problem is the line:

newNode->dword = wordIn;

wordIn is a local array in load. You are storing the address of wordIn in the dword of your nodes. When you return from load, those addresses are no valid any longer.

What you need to do is allocate memory for the string in wordIn, assign the allocated memory to newNode->dword and copy the contents of wordIn to newNode->dword.

If your platform provides the non-standard function strdup, you can change the above line to:

newNode->dword = strdup(wordIn);

If not, it is easily implemented:

char* strdup(char const* in)
{
   char* r = malloc(strlen(in)+1);
   strcpy(r, in);
   return r;
}
Sign up to request clarification or add additional context in comments.

4 Comments

Another issue is int wordSize = sizeof(word); which gives you the size of the pointer, not the length of the string it points to. strlen is what you need there.
Thanks for the info R Sahu. So space should be allocated to hold each char* read into wordIn, then that word is being assigned to newNode->sword if I am understanding your answer correctly? A few questions arise. My first instinct is that it appears memory is allocated twice for each char* (once to read it into wordIn, and then again within the struct newNode to hold the same value). Is this correct? If so, could I just declare wordIn to be a global variable and then the value that is read into wordIn each time simply assigned to the newNode->sword for each node?
Thanks Retired Ninja for catching my sizeof error. I have a face palm mark on my face for the rest of the afternoon. That was a simple one I should have caught but has been staring me in the face this whole time! :)
@wertytrew Answer to Q1: yes. Answer to Q2: No. Memory for wordIn is allocated on the stack and reused for every iteration in the loop. When you read the string into wordIn, new memory is not being allocated for it.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.