0

This is what I happen to get when I run check50, which is weird, because when I do manual tests, I seem to match the keys.

Other posts make me think this might be an issue of using the incorrect slug? I used the one given to me on their website, check50 cs50/problems/2021/x/speller so I am not sure what is happening.

Here are the results.

Results for cs50/problems/2021/x/speller generated by check50 v3.1.2
:) dictionary.c exists
:) speller compiles
:( handles most basic words properly
    expected "MISSPELLED WOR...", not ""
:( handles min length (1-char) words
    expected "MISSPELLED WOR...", not ""
:( handles max length (45-char) words
    expected "MISSPELLED WOR...", not ""
:( handles words with apostrophes properly
    expected "MISSPELLED WOR...", not ""
:( spell-checking is case-insensitive
    expected "MISSPELLED WOR...", not ""
:( handles substrings properly
    expected "MISSPELLED WOR...", not ""
:| program is free of memory errors
    can't check until a frown turns upside down

Here is an example of what I get when I run $ ./speller texts/cat.txt

MISSPELLED WORDS

WORDS MISSPELLED:     0
WORDS IN DICTIONARY:  143091
WORDS IN TEXT:        6
TIME IN load:         0.02
TIME IN check:        0.00
TIME IN size:         0.00
TIME IN unload:       0.01
TIME IN TOTAL:        0.03

So you can see I do start with "MISSPELLED WORDS..." but check50 does not seem to think so? Here are the more detailed results from check50. Why does it show output in my terminal but not in check50?

I have also removed all instances of printf from my dictionary.c code. I haven't changed speller.c either. What can be the problem?

EDIT: Here is my code

// Implements a dictionary's functionality

#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "dictionary.h"

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

// Number of buckets in hash table
const unsigned int N = 100;

// Hash table
node *table[N];

// Keep track of size of dictionary
int s = 0;

// Keep track if dictionary was loaded
bool loaded = false;

// Returns true if word is in dictionary, else false
bool check(const char *word)
{
    // Get hash value for this word
    int h = hash(word);

    // Create temporary node, point it at the first in the linked list
    node *tmp = table[h];
    
    // If there is no linked list at that index in array, word is not in dictionary
    if (tmp == NULL)
    {
        return false;
    }

    // Search through entire linked list for that word, in lowercase
    while (tmp != NULL)
    {
        if (strcasecmp(tmp->word, word) == 0)
            return true;
        else
            tmp = tmp->next;
    }
    return false;
}

// Hashes word to a number
// Source1: djib2 - Dan Bernstein http://www.cse.yorku.ca/~oz/hash.html
// Source2: edit by SocratesSatisfied on https://www.reddit.com/r/cs50/comments/eo4zro/good_hash_function_for_speller/
unsigned int hash(const char *word)
{
    unsigned long hash = 5381;
    int c = *word;
    c = tolower(c);

    while (*word != 0)
    {
        hash = ((hash << 5) + hash) + c;
        c = *word++;
        c = tolower(c);
    }

    // Ensure hash fits in my number of buckets
    return hash % N;
}

// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
    // Open dictionary file
    FILE *file = fopen(dictionary, "r");
    if (file == NULL)
        return false;
        
    // Read strings from file one at a time, read into "w," a character array
    char *w[LENGTH + 1];
    while (fscanf(file, "%s", *w) != EOF)
    {
        // Create new node for each word
        node *n = malloc(sizeof(node));
        if (n == NULL)
            return false;
        strcpy(n->word, *w);
        n->next = NULL;
    
        // Hash word to obtain hash value
        int i = hash(*w);

        // Insert node into hash table at that value
        node *tmp = table[i];
        n->next = tmp;
        table[i] = n;
        
        // Update size of dictionary
        s++;
    }
    // Close file
    fclose(file);

    loaded = true;
    return true;
}

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

// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
    int freed = 0;
    
    // Loop for each linked list in the array
    for (int i = 0; i < N; i++)
    {
        node *cursor = table[i];

        while (cursor != NULL)
        {
            node *tmp = cursor;
            cursor = cursor->next;
            free(tmp);
        }
        freed++;
    }
    if (freed == N)
        return true;
    else
        return false;
}
4
  • No way to know without seeing the actual code. – Cliff B Feb 6 at 9:22
  • Make sure you run tests with the small dictionary. Does it seg fault? – DinoCoderSaurus Feb 6 at 11:56
  • @CliffB I edited and put in my code! – Summer Ng Feb 7 at 2:17
  • @DinoCoderSaurus I tried with small dictionary and it doesn't seg fault... I am very confused – Summer Ng Feb 7 at 2:18
1

This is a strange one. Can't get it to seg fault in the IDE, but it consistently seg faults in check50. So, I embedded some printf statements in the code to track down where it is happening in check50 and looking at the output on the website link that check50 returned.

The underlying problem is with "w". Look at the declaration:

char *w[LENGTH + 1];

This means that w is an array of "Length + 1" pointers, not an array of characters. That leads to very unpredictable results, since later code is trying to store data directly in the pointers.

Instead, a char array should be created.

char w[LENGTH + 1];

This will resolve the issues. In short remove the asterisks from "*w" in the code and use w as a char array instead of a pointer array.

Finally, a programming tip. Single letter variable names should be avoided, except as counters in for loops. Descriptive var names should be used. In this case, "word".

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

1
  • Thank you SO MUCH! As a new programmer, I was confused why it would work for me but not for check50. Hopefully with practice I can get to your level. Also, thank you for the tip about the variable names, I will update that too. (: – Summer Ng Feb 7 at 17:17

You must log in to answer this question.

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