0

I am having problems with Pset 5 Speller. I believe, I'm nearly there, I can get all functions to run and compile successfully, however my outputs are not quite right. I have attached comments to make it as easy to follow as possible. Any ideas what the issue might be? I'm thinking the load function might be the problem as word in dictionary returns: 0

Here is my Check50 response:

:) dictionary.c, dictionary.h, and Makefile exist
:) 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
    expected "MISSPELLED WOR...", not "MISSPELLED WOR..."
:| program is free of memory errors
    can't check until a frown turns upside down

Here is my Output

WORDS MISSPELLED: 17756 WORDS IN DICTIONARY: 0
WORDS IN TEXT: 17756 TIME IN load: 0.00 TIME IN check: 0.01 TIME IN size: 0.00 TIME IN unload: 0.00 TIME IN TOTAL: 0.01

Here is my code:

// Implements a dictionary's functionality
#include <stdbool.h>
#include "dictionary.h"
#include <strings.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <ctype.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 = no of hashcodes
const unsigned int HTSize = 10;

// Hash table
node *hashtable[HTSize];

//Global Variables Defined
int word_count;
FILE* input = NULL;


// Hashes word to a number HASH FUNCTION
unsigned int hash(const char *word)
{
    unsigned int hash_value = 0;
    for (int i = 0, length = strlen(word); i < length; i++)
    {
         hash_value = (hash_value << 2) ^ word[i];
    }
    return hash_value % HTSize; //N is size of hashtable
}


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

    //Creates a pointer from word pointing to NULL
    char *word = NULL;
    while (fscanf(input, "%s", word) == 1)
    {
        //For each word in the dictionary, allocate mem and create a new node, check pointer is NULL
        node *new_node = malloc(sizeof(node));
        if (new_node == NULL)
        {
            printf("Could not allocate memory");
            return false;
        }
        else
        {
            //Copy the word stored in the buffer to the new node and initialize the nodes value fields
            strcpy(new_node->word, word);
            new_node->next = NULL;

            // Calculates hashcode of word in buffer using hash function ready for insertion into hashtable
            unsigned int hash_code = hash(word);

            // Initializes head to point to hashtable index/bucket
            node *head = hashtable[hash_code];

            // If no node in the Singly-Linked-List, add a new node
            if (head == NULL)
            {
                hashtable[hash_code] = new_node;
                word_count++;
            }
            else // If already a node present, re-arrange pointers to not orphan memory
            {
                new_node->next = hashtable[hash_code];
                hashtable[hash_code] = new_node;
                word_count++;
            }
        }
    }
    fclose(input);
    return true;
}


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


// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
    node *head = NULL;
    node *cursor = head;

        while (cursor != NULL)
        {
            node* tmp = cursor;
            cursor = cursor->next;
            free(tmp);
        } return true;
}

// Returns true if word is in dictionary else false
bool check(const char *word)
{
    //declares a string to hold a word converted to lowercase for hashing
    char tmpword[LENGTH+1];
    int n = strlen(word);
    for(int i = 0; i < n+1; i++)
    {
        tmpword[i] = tolower(word[i]);
    }
    tmpword[LENGTH] = '\0';

    // Create temp variable to house and locate hash value
    int hash_code = hash(word);

    //Search for a word in the linked list, linked to hashtable element
    if (hashtable[hash_code] == NULL)
    {
        return false;
    }
    else if (hashtable[hash_code] != NULL)
    {
        //Create a node cursor pointing to 1st node in hashtable
        node *cursor = hashtable[hash_code];
        while (cursor != NULL)
        {
            if (strcasecmp(cursor->word, word) == 0)
            {
                return true;
            }
            else
            {
                cursor = cursor->next;
            }
        }
    } return false;
}

1 Answer 1

0

This fscanf(input, "%s", word) == 1 never evaluates to true.

The return value is described in man fscanf as:

These functions return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.

But it cannot assign anything to word.

According to the description of the s directive from the man page [emphasis added]

Matches a sequence of non-white-space characters; the next pointer must be a pointer to character array that is long enough to hold the input sequence and the terminating null byte ('\0'), which is added automatically. The input string stops at white space or at the maximum field width, whichever occurs first.

word has to (m|c)alloc'd or a char array that is long enough to handle the longest word.

You must log in to answer this question.

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