0

Think I've managed to get everything to work. The program compiles and loads large or small dictionaries and finds misspelled words in various text files.

I diffed the output of my speller with staff's implementation and besides the time differences, I consistently have an extra word in the dictionary. I believe it might be something to do with me using the feof() function in load(), but can't be sure. The rest of the output is exactly the same as staff's program.

Check50 is red and frowning all the way though. Not sure what is going on. Please have a look at my code.

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

#include "dictionary.h"

// size of the hash table
#define TABLESIZE 27

// size of the dictionary
unsigned int dictSize = 0;

// build the node for the hash table
typedef struct node
{
    char word[LENGTH+1];
    int hashkey;
    struct node* next;
}
node;

// construct the root node array of the hash table
node* hashtable[TABLESIZE];


// simple hash function
int hash(const char* word)
{
    return abs(toupper(word[0]) - 'A');
}

/**
 * Returns true if word is in dictionary else false.
 */
bool check(const char* word)
{
    // convert the word to lowercase before checking the dictionary
    char lowercase[LENGTH+1];

    for(int i = 0, j = strlen(word) + 1; i < j; i++)
    {
    lowercase[i] = tolower(word[i]);
}

//walk through the dictionary
int index = hash(lowercase);

for(node *ptr = hashtable[index]; ptr != NULL; ptr = ptr->next)
{
    if(strcmp(lowercase, ptr->word) == 0)
    {
        return true;
    }
}
return false;
}

/**
 * Loads dictionary into memory.  Returns true if successful else false.
 */
bool load(const char* dictionary)
{
    for (int i = 0; i < TABLESIZE; i++)
    {
        hashtable[i] = NULL;
    }

//open the dictionary file
FILE* dPtr = fopen(dictionary, "r");
if (dPtr == NULL)
{
    printf("Could not open dictionary file.\n");
    unload();
    return 1;
}

//assign values to the node
while(!feof(dPtr))
{
    node* newNode = malloc(sizeof(node));
    if (newNode == NULL)
    {
        exit(1);
    }
    fscanf(dPtr, "%s", newNode->word);
    newNode->hashkey = hash(newNode->word);
    newNode->next = hashtable[newNode->hashkey];
    hashtable[newNode->hashkey] = newNode;

    dictSize++;

    if(feof(dPtr))
    {
        fclose(dPtr);
        return true;
    }
}

return false;
}

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

/**
 * Unloads dictionary from memory.  Returns true if successful else false.
 */
bool unload(void)
{
for (int i = 0; i < TABLESIZE; i++)
{
    node* cursor = hashtable[i];

    while(cursor != NULL)
    {
        node* temp = cursor;
        cursor = cursor->next;
        free(temp);
    }
}

return true;
}

Excuse me for pasting the whole dictionary.c here, but I'm really not sure why it keeps failing check50.

1 Answer 1

0

Well, you diagnosed it yourself. You have one extra word in the dictionary, making the word count wrong. You can definitely be sure it has something to do with the feof() function, but you may not understand why.

Your code logic is essentially this:

  1. read a word
  2. copy the word to a node
  3. check to see if EOF has been hit.

In other words, " ready, fire, aim."

The EOF condition doesn't actually trigger until it's truly encountered. With the fgets(), it reads the last word, which goes right up to the EOF, but it doesn't actually detect the EOF until the next read. So, after reading the last word, the code executes another read with fgets(), creates another node and copies, ummm... I'm not sure what... into the new node, increments the word count and circles back to the top of the loop where the EOF is finally detected.

Two ways to fix this. One is to check for EOF immediately after the read. Another is to incorporate the read into the while loop, simultaneously checking the return value for an EOF condition.

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

1
  • I've refactored the code to use fgets() instead of fscanf(), so I could incorporate the read and EOF condition into the while loop. It works much better now, almost all the frowns are now smiles. But, still one more corner case to go, the longest word. Must be something trivial, I'll iterate some more. Thanks for pointing the way.
    – raj34
    Commented Feb 17, 2016 at 12:43

You must log in to answer this question.

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