Skip to main content
4 of 6
added 11 characters in body

pset5 speller cannot read number of word in dictionary

thank you for clicking. Being concise, I have the right solution for the pset, as evidenced down below by comparing my solution to the staff's, but check50 insists that no words have been loaded into the dictionary.

Commands from pset5 testing section:

./speller texts/lalaland.txt > student.txt
./speller50 texts/lalaland.txt > staff.txt
diff -y student.txt staff.txt

When these are run, it shows me the differences between the outputs of both programs with an '|' or '>' character in the beginning of the line.

2023/week5/prob/speller/ $ ./speller texts/lalaland.txt > student.txt
2023/week5/prob/speller/ $ ./speller50 texts/lalaland.txt > student.txt
2023/week5/prob/speller/ $ diff -y student.txt staff.txt

MISSPELLED WORDS                                                MISSPELLED WORDS

Chazelle                                                        Chazelle
L                                                               L
TECHNO                                                          TECHNO
L                                                               L
Thelonious                                                      Thelonious
Prius                                                           Prius

... for the sake of brevity (there are a lot of words mispelled).

Mia                                                             Mia
Mia                                                             Mia
Sebastian's                                                     Sebastian's
L                                                               L

WORDS MISSPELLED:     955                                       WORDS MISSPELLED:     955
WORDS IN DICTIONARY:  143091                                    WORDS IN DICTIONARY:  143091
WORDS IN TEXT:        17756                                     WORDS IN TEXT:        17756
TIME IN load:         0.02                                      TIME IN load:         0.02
TIME IN check:        0.01                                      TIME IN check:        0.01
TIME IN size:         0.00                                      TIME IN size:         0.00
TIME IN unload:       0.01                                      TIME IN unload:       0.01
TIME IN TOTAL:        0.04                                    | TIME IN TOTAL:        0.03

As we both can observe, the only difference between my code and the staff is the running time. Therefore, I have reason to believe that my code is correct. Here is what check50 has to say about that.

2023/week5/prob/speller/ $ check50 cs50/problems/2023/x/speller
Results for cs50/problems/2023/x/speller generated by check50 v3.3.8
:) dictionary.c exists
:) speller compiles
:( handles most basic words properly
    expected "MISSPELLED WOR...", not "MISSPELLED WOR..."
:( handles min length (1-char) words
    expected "MISSPELLED WOR...", not "MISSPELLED WOR..."
:( handles max length (45-char) words
    expected "MISSPELLED WOR...", not "MISSPELLED WOR..."
:( handles words with apostrophes properly
    expected "MISSPELLED WOR...", not "MISSPELLED WOR..."
:( spell-checking is case-insensitive
    expected "MISSPELLED WOR...", not "MISSPELLED WOR..."
:) handles substrings properly
:) program is free of memory errors

I have tested my code with different dictionaries, different texts, fed those same parameters to the staff's solution and again, apart from running time, the number of words mispelled and such are the same.

Take a look at this check50 prompt. Pasting code doesn't work nicely so a picture it is.

There is one word in the text. The program is supposed to take a look at the word in the text, and see if it appears in the dictionary. If it doesn't, that means the word is MISPELLED: it is printed out to the screen under MISSPELLED WORDS and the respective count rises by one. Else, if it does appear, then that means the word is not MISPELLED, therefore the word isn't printed out and the counter isn't updated.

In the "expected output", there is one word in the dictionary, which happens to be the one word in the text. Therefore, no words are mispelled: the mispelled words counter stay at zero.

In the "actual output", there are NO words in the dictionary, and one word in the text. Therefore, since the one word in the text isn't in the dictionary, because there are no words in the dictionary, the one word of the text is MISPELLED and printed out to the screen.

Except, that isn't the case. The word is checked correctly. I feel like that is... impossible. You can probably see the gap of logic there.

As I keep looking at the check50 log's, I see that the outputs of the "expected output" and my "actual output" are the same, EXCEPT for the number of WORDS IN DICTIONARY. It is always zero.

I chucked it up to "Oh well, I did something wrong. Better move stuff around and see what sticks."

That was 4 hours ago. I have tried a lot: moving the unload function around, editing speller.c (it is up to date, the problem is not there), checking if the load function recieves the correct dictionary and not the default one, messing with the size funcion, etc...

Debugging, for me, is just a matter of time, patience and concentration. I don't watch the shorts. I have never looked at the hints section except for practice problems. I have never watched a walkthrough. I always took the bare minimum and thought, or researched, from there because I felt more accomplished with getting perfect check50 scored with as little help as possible.

This one, however, I am truly stuck. I have done all of the above and more for this one.

Pset5 has cut too much into my time allocated for week6, for something that I feel that is outside my control. I would greatly and truly appreciate for you to shed light on this issue.

  Sincerely, a confused CS50x student.

My code for dictionary.c is below.

    // Implements a dictionary's functionality

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

#include "dictionary.h"

// Represents a node in a hash table
typedef struct node
{
    char word[LENGTH + 1];
    struct node *next;
} node;

// TODO: Choose number of buckets in hash table
const unsigned int N = 50492;

// Hash table
node *table[N];

// Returns true if word is in dictionary, else false
bool check(const char *word)
{
    int j = strlen(word);
    char nword[j];
    nword[j] = '\0';
    for (int i = 0; i < j; i++)
    {
        nword[i] = tolower(word[i]);
    }
    for (node *ptr = table[hash(word)]; ptr != NULL; ptr = ptr->next)
    {
        if (strcmp(nword, ptr->word) == 0)
        {
            return true;
        }
    }
    return false;
}

// Hashes word to a number
unsigned int hash(const char *word)
{
    // TODO: Improve this hash function
    int hashArr[LENGTH + 1] = {139, 137, 127, 113, 109, 107, 103, 101, 97, 89, 83, 79, 73, 71, 67, 61, 59, 53, 47, 43, 41, 31, 29,
                               23,  19,  13,  7,   3,   2,   1,   1,   1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1};
    int num = 0;
    for (int i = 0; word[i] != '\0'; i++)
    {
        if (word[i] == '\'')
        {
            continue;
        }
        num += hashArr[i] * (tolower(word[i]) - 'a');
    }
    return num;
}

// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
    for (int i = 0; i < N; i++)
    {
        table[i] = NULL;
    }
    FILE *dict = fopen(dictionary, "r");
    if (dict == NULL)
    {
        return false;
    }
    node *ptr = NULL;
    char c;
    int idx = 0, h_idx = 0;
    char nword[LENGTH + 1];
    while (fread(&c, 1, 1, dict))
    {
        // end of line
        if (c == '\n')
        {
            nword[idx] = '\0';
            idx = 0;
            ptr = malloc(sizeof(node));
            if (ptr == NULL)
            {
                return false;
            }
            h_idx = hash(nword);
            ptr->word[0] = nword[0];
            for (int i = 1; nword[i - 1] != '\0'; i++)
            {
                ptr->word[i] = nword[i];
            }
            ptr->next = table[h_idx];
            table[h_idx] = ptr;
        }
        // else append char into word buffer
        else if (isalpha(c) || c == '\'')
        {
            nword[idx] = c;
            idx++;
        }
    }
    fclose(dict);
    return true;
}

// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
    // if cat hash not accessed, then dict not loaded
    if (table[hash("cat")] == NULL)
    {
        return 0;
    }
    int count = 0;
    for (int i = 0; i < N; i++)
    {
        for (node *ptr = table[i]; ptr != NULL; ptr = ptr->next)
        {
            count++;
        }
    }
    return count;
}

// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
    node *ptr;
    for (int i = 0, lcount = 0; i < N; i++)
    {
        ptr = table[i];
        while (ptr != NULL)
        {
            node *cursor = ptr;
            ptr = ptr->next;
            free(cursor);
        }
    }
    return true;
}