I'm currently at the CS50's pset5, and am working on the "Speller" problem. I managed to do all functions and don't have any compile or runtime errors. When using check50, though, I receive a sad face (:() on the last line, saying:
:( program is free of memory errors valgrind tests failed; see log for more information.
When I click on the link provided by check50, that's the output for the valgrind:
running valgrind --show-leak-kinds=all --xml=yes --xml-file=/tmp/tmph5epgoz9 -- ./speller substring/dict substring/text...
checking for output "MISSPELLED WORDS\n\nca\ncats\ncaterpill\ncaterpillars\n\nWORDS MISSPELLED: 4\nWORDS IN DICTIONARY: 2\nWORDS IN TEXT: 6\n"...
checking that program exited with status 0...
checking for valgrind errors...
168 bytes in 3 blocks are still reachable in loss record 1 of 1: (file: dictionary.c, line: 80)
Line 80 in my code is part of the load() function that I've completed. This is it:
node *new = malloc(sizeof(node)); // create a new last element in the linked list
Also, here's my full dictionary.c code:
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "dictionary.h"
int sz = -1;
// 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 = 26;
// Hash table
node *table[N];
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
    // TODO
    int key = hash(word);
    node* curr = table[key];
    while (curr != NULL)
    {
        if (strcasecmp(word, curr->word) == 0)
        {
            return true;
        }
        curr = curr->next;
    }
    return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
    // TODO
    return tolower(word[0]);
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
    // TODO
    int isRoot[N];
    for (int i = 0; i < N; i++)
    {
        isRoot[i] = 1;
        table[i] = NULL;
    }
    FILE *f;
    if ((f = fopen(dictionary, "r")) == NULL)
    {
        return false;
    }
    char word[LENGTH+1];
    while (!feof(f)) // go through the whole dictionary file
    {
        fscanf(f, "%s", word);
        int key = hash(word); // hash the word
        node *new = malloc(sizeof(node)); // create a new last element in the linked list
        if (new == NULL) // check if malloc() worked properly
        {
            return false;
        }
        strcpy(new->word, word);
        // move the data into the new linked list element
        if (isRoot[key] == 1)
        {
            new->next = NULL;
            table[key] = new;
            isRoot[key] = 0;
        }
        else
        {
            new->next = table[key];
            table[key] = new;
        }
        sz++;
    }
    fclose(f);
    return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
    // TODO
    return sz;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
    // TODO
    int i;
    for (i = 0; i < N; i++)
    {
        node* curr = table[i];
        while (curr != NULL)
        {
            node* tmp = curr;
            curr = curr->next;
            free(tmp);
        }
        if (curr != NULL)
        {
            return false;
        }
    }
    return true;
}
I firstly thought it might be from the unload() function, but looked up on several similar Stack Overflow questions and I had the exact algorithm for the unload() function (the right one). I don't know what I did wrong. Did I forget to free() memory somewhere? Doesn't my unload() function free all the memory I've allocated with malloc()?
Help would be appreciated. Thank you.
