0

so currently my speller seems to be working, it matches the staff solution with the austinpowers.txt (correctly identifies that 644 words have been misspelled & works when using a small dictionary & a test text file)

However, when running check50 it fails all checks saying that there was no actual output - i'm not sure where to go from here, i've looked online at reducing load time, changing little bits in the code but have come up unsuccessful so far. Any help would be much appreciated. Thanks guys!

:) dictionary.c, dictionary.h, and Makefile exist :) speller compiles :( handles most basic words properly expected "MISSPELLED WORD...", not "" :( handles min length (1-char) words expected "MISSPELLED WORD...", not "" :( handles max length (45-char) words expected "MISSPELLED WORD...", not "" :( handles words with apostrophes properly expected "MISSPELLED WORD...", not "" :( spell-checking is case-insensitive expected "MISSPELLED WORD...", not "" :( handles substrings properly expected "MISSPELLED WORD...", not ""

Here's the check50:

https://cs50.me/checks/2607aa8d0c8ab84b41bcf0ed7c981c8e8ace84e6

& here's the code:

/**
 * Implements a dictionary's functionality.
 */
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "dictionary.h"

#define DICTIONARYSMALL "dictionaries/small"
#define DICTIONARY "dictionaries/large"
#define BUCKETSIZE 5000

// define word
char word[LENGTH + 1];

// hash function, uses multiplication.
int hash(const char *word)
{
    unsigned int index = 0;
    for (int i=0, n=strlen(word); i<n; i++) {
        index = (index << 2) ^ word[i];
    }
    return index % BUCKETSIZE;
}

// defining the type node, to be used for linked list'
typedef struct node
{
    char word[LENGTH + 1];
    struct node *next;
}
node;

// size of hashtable (which will be size of the alphabet)
node *hashtable[BUCKETSIZE];

/**
 * Returns true if word is in dictionary else false.
 */
bool check(const char *word)
{

    char new_word[strlen(word)];
    strcpy(new_word, word);

    for (int i = 0; new_word[i] != '\0'; i++)
    {
        new_word[i] = tolower(new_word[i]);
    }

    for (int i = 0; word[i] != '\0'; i++)
    {
        if (!isalpha(word[i]) && word[i] != '\'')
        {
            return false;
        }
    }

    // cursor which points to the first entry in hashtable index 
    int index = hash(new_word);
    node *cursor = hashtable[index];

    while (cursor != NULL)
    {
        if (strcmp(cursor->word, new_word) == 0)
        {
            return true;
        }

        cursor = cursor->next;
    }

    return false;
}

/**
 * Loads dictionary into memory. Returns true if successful else false.
 */
bool load(const char *dictionary)
{

    // get all arrays in dictionary to initialize to NULL
    for (int i = 0; i < BUCKETSIZE; i++)
    {
        hashtable[i] = NULL;
    }

    node *head = NULL;

    // open our dictionary tru
    FILE *file = fopen(DICTIONARY, "r");

    while(fscanf(file, "%s", word) != EOF)
    {

        // new node - will use chaining to solve issue if two data types end up in same bucket
        node *new_node = malloc(sizeof(node));
        // check to make sure node has shiz in it.
        if (new_node == NULL)
        {
            unload();
            return false;
        }

        strcpy(new_node->word, word);
        int index = hash(new_node->word);
        // case for if hashtable[i] is not pointing to any current word (linked list is empty in that array)
        if (hashtable[index] == NULL)
        {
            head = hashtable[index];
            hashtable[index] = new_node;
            new_node->next = NULL;
        }

        // case for when hashtable[i] is pointing to word, i.e. wanna insert new item into linked list
        else if (hashtable[index] != NULL)
        {
            new_node->next = hashtable[index];
            hashtable[index] = new_node;
        }

        if (feof(file))
        {
            break;
        }

    }

    fclose(file);

    return true;

}

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

    FILE *file = fopen(DICTIONARY, "r");

    while(fscanf(file, "%s", word) != EOF)
    {
        words++;
    }

    return words;
}

/**
 * Unloads dictionary from memory. Returns true if successful else false.
 */
bool unload(void)
{

    node *cursor = hashtable[0];

    for (int i = 0; i < BUCKETSIZE; i++)
    {
        cursor = hashtable[i];
        while (cursor != NULL)
        {
            node* temp = cursor;
            cursor = cursor->next;
            free(temp);
        }
    }

    return true;
}
2
  • Have you altered speller.c at all? While I haven't done an indepth analysis, it almost seems like there's a stray printf statement somewhere that's adding a line feed or something. Could be something totally different though.
    – Cliff B
    Aug 8, 2017 at 2:18
  • I don't think I have, but that's something that would be worth considering - I had a quick look before but nothing stood out to me that I might've accidentally changed! But who knows, could be something in there haha Aug 8, 2017 at 10:58

1 Answer 1

0
char new_word[strlen(word)];

should be

char new_word[strlen(word) + 1];

as you need to include the null terminator, which is not part of the length as reported by strlen.

You don't use the head variable. The whole block

        // case for if hashtable[i] is not pointing to any current word (linked list is empty in that array)
        if (hashtable[index] == NULL)
        {
            head = hashtable[index];
            hashtable[index] = new_node;
            new_node->next = NULL;
        }

        // case for when hashtable[i] is pointing to word, i.e. wanna insert new item into linked list
        else if (hashtable[index] != NULL)
        {
            new_node->next = hashtable[index];
            hashtable[index] = new_node;
        }

could be shortened to

        new_node->next = hashtable[index];
        hashtable[index] = new_node;

I'm not really convinced by that EOF and feof logic. One of them, done at the right place, should work. At least the feof is in the wrong place, would need to come instantly after the read operation. (And doesn't fscanf return the number of matched patterns (so here 0 or 1), so the condition in while is always true?) No, it doesn't, this usage of fscanf is probably right as long as lines in file obey the line length limit

size should not read the dictionary file, but return the number of words already stored in the dict. You could keep a global counter variable and increment it each time you read a word.

3
  • Hey, so I've taken upon the considerations you've given me & it's made the code much more sleek and got rid of the time taken in the size function! I'm not sure with what to do with the EOF loop though, i've gotten rid of the feof and the code compiles fine & has the same output as before (644 words misspelled etc.). I thought that this would work, but i'm still getting the same error as before i.e. :( handles most basic words properly expected "MISSPELLED WORD...", not "" Any more that could be done? Thank you heaps for the help so far! Aug 8, 2017 at 10:57
  • lmao, so it's cos when i was opening the file i was opening 'DICTIONARY' which i defined to be "dictionaries/large", changing it to 'dictionary' fixed it up & now it passes all the checks - thanks for the help ! Aug 8, 2017 at 11:28
  • The use of fscanf seems correct, I must have confused that with another function. I compared the output of your programme, and it seems the same as mine, as long as I use the large dict. There's no use for DICTIONARYSMALL and DICTIONARY macros, remove them, and use dictionary in load (if you count the words on loading, there's no need for the file name in size). valgrind seems happy with my changes.
    – Blauelf
    Aug 8, 2017 at 11:41

You must log in to answer this question.

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