0

My speller program has an issue where it will find what words are misspelled properly, but it won't give the data of the amount of words misspelled/ in the dictionary/ in text. Running Check50 shows me this as well.

Could not find the following in the output:

MISSPELLED WORDS
ca
cats
caterpill
caterpillars

WORDS MISSPELLED:     4
WORDS IN DICTIONARY:  2
WORDS IN TEXT:        6

While this is what my program returns

Actual Output:

MISSPELLED WORDS

ca
cats
caterpill
caterpillars

It gets the words that are misspelled but it doesn't actually print out how many are misspelled. To further find the issue, I compared my output to the answer key with

diff -y student.txt keys/lalaland.txt

and found that my program works fine until a certain word, where it then just stops.

```
/// no issues before this point
Barista                                                         Barista
Mia                                                             Mia
INT                                                             INT
s                                                               s
Carson's                                                        Carson's
How'd                                                           How'd
                                                              > MARMONT
                                                              > Mia
                                                              > INT
                                                              > MARMONT
                                                              > Mia
                                                              > Mia's
```

I suspect that the reason why I'm not getting the numbers of words returned to me is because somewhere along the way, my code is stuck, but I have no idea how. Here is my code:

// Implements a dictionary's functionality

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

#include "dictionary.h"

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

int dictionaryTotal = 0;

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

// Hash table
node *table[N];

// Returns true if word is in dictionary, else false
bool check(const char *word)
{
    // TODO
    bool wordPresent = false;
    int hashIndex = hash(word);

    if (table[hashIndex] != NULL)
    {
        wordPresent = true;
    }

    node *cursor = malloc(sizeof(node));
    cursor = table[hashIndex];
    while (cursor != NULL && wordPresent == true)
    {
        //printf("word: %s\n", word);
        //printf("cursor->word: %s\n", cursor->word);
        if (strcasecmp(word, cursor->word) == 0)
        {
            //printf("word found\n");
            return true;
        }
        cursor = cursor->next;
    }

    //printf("word not found\n");
    return false;
}

// Hashes word to a number
unsigned int hash(const char *word)
{
    // TODO: Improve this hash function
    int hashSum = 0;
    const int letterCount = 2;
    int lettersCounted = 0;

    int wordLength = strlen(word);
    char *tempWord = malloc(sizeof(char*) * wordLength);
    strcpy(tempWord, word);
    // char tempWord[wordLength];

    // makes it not case sensitive
    for (int i = 0; i < wordLength; i++)
    {
        tempWord[i] = tolower(word[i]);
    }

    //generates hash code based on first two letters' ascii code sum
    for (int i = 0; i < letterCount; i++)
    {
        if (tempWord[i] >= 'a' && tempWord[i] <= 'z')
        {
            hashSum += tempWord[i];
            lettersCounted += 1;
        }
    }
    hashSum = hashSum - (lettersCounted * ('a'));
    free(tempWord);
    return hashSum;


    //return toupper(word[0]) - 'A';
}

// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
    // TODO
    FILE *input = fopen(dictionary, "r");
    if (input == NULL)
    {
        return false;
    }

    char buffer[LENGTH];

    // Initialize all pointers in hash to be NULL
    for (int i = 0; i < N; i++)
    {
        table[i] = NULL;
    }

    while (fscanf(input, "%s", buffer) != EOF)
    {

        //printf("%s\n", buffer);
        int hashIndex = hash(buffer);
        //printf("%i\n", hashIndex);
        node *cursor = malloc(sizeof(node));

        // counts the amount of words in dictionary
        dictionaryTotal += 1;

        //initialize values of the node
        for (int i = 0, length = strlen(buffer); i < length;i ++)
        {
            cursor->word[i] = buffer[i];
        }

        // adds first node if none are present
        if (table[hashIndex] == NULL)
        {
            cursor->next = NULL;
        }

        // prepends if hashtable is present
        if (table[hashIndex] != NULL)
        {
            cursor->next = table[hashIndex];
        }

        //sets hashIndex to point to the same place as our cursor to lock it in and we are now able to reintialize cursor essentially resetting it
        table[hashIndex] = cursor;
    }
    fclose(input);
    return true;

}

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

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

    // checks each hash to see if they're all null. if any are not NULL, return false.
    for(int i = 0 ; i < N; i ++)
    {
        if (table[i] != NULL)
        {
            return false;
        }
    }

    return true;
}

1
  • walk through the code with a debugger and figure out why its exiting. have you tried that?
    – UpAndAdam
    Commented Aug 21, 2023 at 18:15

1 Answer 1

0

minor items:
You shouldn't be malloc'ing in check, you are leaking that memory and you don't need it. Simply do not malloc there.

In load function you are using a for loop to copy the 'word' into the cursor's word... just use strcpy.

Then in load this

// adds first node if none are present
if (table[hashIndex] == NULL)
{
    cursor->next = NULL;
}

does not add the first node, and doesnt do anything good useful.

Major Issue

During your unload you again are malloc'ing for no reason and leaking memory. And you are breaking your list horribly and not freeing it properly. But more importantly you have an infinite loop

while (table[i] != NULL)
{
    node *cursor = malloc(sizeof(node));
    cursor = table[i]; // you just leaked the memory you allocated above
    while (cursor->next != NULL) //not what you should check check that cursor != NULL
    {
        cursor=cursor->next;
    }
    free(cursor);  //ok you free'd it, but this doesnt change the value of the prior Node's next pointer, it will continue to point to this now freed address which will result in undefined behavior or infinite loop or a double free.
}

I suggest you put some print statements inside your unload to see if its doing what you think it's doing and you will find out what your problem is.

You must log in to answer this question.

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