0

I've looked over the code, but I would think I'm doing everything perfectly, I'm not sure whats wrong.

The cs50 checker says I always have 46 words in the dictionary, and while my words in text is always right, my words misspelled is wrong a majority of the time. Its hard because I don't know what functions words misspelled and words in dictionary mostly use.

// Implements a dictionary's functionality

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

#include "dictionary.h"

//Added a word count here for my size function. I had to put it at the top because it wasn't working in the load function because of scope
    int word_count = 0;

// 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
//As I'm looking at the length of the words for my hash table, the number of buckets should be 1 less than the maximum length, 45
const unsigned int N = 44;

// Hash table
node *table[N];

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

    //Hash word to obtain a hash value
    int hash_word = hash(word);

    //Access linked list at that index in the hash table
    node *cursor = table[hash_word];

    //Traverse linked list as long as the cursor pointer isn't NULL, or at the end of the words in the index
    while (cursor != NULL)
    {
        //Compare the word with the word in the index.
        if (strcasecmp(word, cursor->word) == 0)
        {
            return true;
        }
        //Go to the next word to compare every word in the index
        cursor = cursor->next;
    }

    return false;
}

// Hashes word to a number
unsigned int hash(const char *word)
{
    // TODO: Improve this hash function

    //Set up a letter count so it can be returned at the end
    int letter_count = 0;

    //Set up a pointer pointing to the word
    const char *p = word;

    //From the cs50 Manual Pages. Strlen in order to find the length of the word
    size_t strlen(const char *p);

    //Update the letter count until it matches the length
    for (int i = 0; i < strlen(p); i++)
    {
        letter_count++;
    }

    return letter_count;
}

// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
    // TODO

    //Open the dictionary file and check if the return value is NULL
    FILE *file = fopen("dictionary.h", "r");
    if (file == NULL)
    {
        return false;
    }
    else if (file != NULL)
    {
        //For the 3rd argument in fscanf. The array is the same as word in the node
        char buffer[LENGTH + 1];

        //To store the value the hash function gives us
        int hash_num = 0;

        //Do as long as the file hasn't finished being read
        while (fscanf(file, "%s", buffer) != EOF)
        {
            //Create a new node for each word
            node *n = malloc(sizeof(node));
            if (n == NULL)
            {
                return false;
                break;
            }
            if (n != NULL)
            {
                //Copy the word into new node
                strcpy(n->word, buffer);

                //Obtain the hash value
                hash_num = hash(buffer);

                //Insert word into hash table at that index
                //The word may be the first one at that index
                if (table[hash_num] == NULL)
                {
                    table[hash_num] = n;
                }
                else if (table[hash_num] != NULL)
                {
                    n->next = table[hash_num];
                    table[hash_num] = n;
                }

            //update word count
            word_count++;

            }
        }
        fclose(file);
        return true;
    }
    else
    {
        return false;
    }
}

// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
    // TODO
    //I got the word count from the load function
    return word_count;
}

// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
    // TODO
    //Loop across all of the indexes in the hash table using N, the number of buckets
    for (int i = 0; i < N; i++)
    {
        //With the walkthrough video, my nodes, (temp and cursor), should be at the first index
        node *temp = table[i];
        node *cursor = table[i];

        //We should stop when temp is NULL, not cursor, as temp is what were freeing.
        //Cursor should move by one before temp is freed and temp goes to where cursor is.
        while (temp != NULL)
        {
            cursor = cursor->next;
            free(temp);
            temp = cursor;
        }
    }
    //We returned the memory successfully!! :D
    return true;
}

Faith
  • 21
  • 2
  • 1
    This is a good opportunity for you to start familiarizing yourself with [using a debugger](https://stackoverflow.com/q/25385173/328193). When you step through the code in a debugger, which operation first produces an unexpected result? What were the values used in that operation? What was the result? What result was expected? Why? To learn more about this community and how we can help you, please start with the [tour] and read [ask] and its linked resources. – David Jun 24 '23 at 16:45
  • 2
    Your `hash` function can return an index out of bounds of the hash-table array. The loop inside it is not needed, it's equivalent to `letter_count = strlen(word);`. And don't create a forward declaration of the `strlen` function, that's already done by the standard `` header file. And `` is a non-standard header file that should not be needed. – Some programmer dude Jun 24 '23 at 16:51
  • In the `load` function, there's no need for the `else if (file != NULL)`. You do the same thing in multiple places, increasing nesting when it's not needed. The `return` statement returns *immediately*, there's no need for a `break` after `return false;`; The `break` will never happen. – Some programmer dude Jun 24 '23 at 16:55
  • 2
    But the biggest issue I can see is that when you add the first node in a bucket, you never initialize `n->next`. It's left uninitialized and with an indeterminate value. You will then attempt to dereference it and that will lead to undefined behavior. – Some programmer dude Jun 24 '23 at 16:59
  • @Someprogrammerdude I have taken away the `else if (file != NULL)` and through looking over fix it. Thank you so much for helping, @David, I was able to use the debugger to help fix my code. It's just that I normally have a problematic time with it. – Faith Jun 24 '23 at 17:33
  • Style note: consider that whe it comes to control flow `void foo(int n) { if (n == 0) { return; } else { blah(); blah(); } }` is equivalent to `void foo(int n) { if (n == 0) { return;} blah(); blah(); }` – Chris Jun 24 '23 at 17:56
  • 1
    Per S.P.D., to fix your two biggest bugs: `unsigned int hash(const char *word) { unsigned int hash_num = 0; for (; *word != 0; ++word) hash_num += *word; return hash_num % N; }` Note that the `% N` is _critical_. And, in `load`, remove the `if/else if` and just _always_ do: `n->next = table[hash_num]; table[hash_num] = n;` Also, see my cs50 speller answer: [cs50 pset5 Speller optimisation](https://stackoverflow.com/a/71316468/5382650) – Craig Estey Jun 24 '23 at 18:05

0 Answers0