I am currently taking CS50 and working on the Speller questions. I am able to get the code to work but the program fails the valgrind test on check50.
Valgrind tells me the leak of 56bytes is at line 86 where I declared a malloc to store the words as the program scans through the dictionary.
I tried doing a fclose at the end of the while loop but it messes up the code.
==75771== HEAP SUMMARY:
==75771== in use at exit: 7,703,248 bytes in 137,558 blocks
==75771== total heap usage: 143,096 allocs, 5,538 frees, 8,023,256 bytes allocated
==75771==
==75771== 7,703,248 bytes in 137,558 blocks are still reachable in loss record 1 of 1
==75771== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==75771== by 0x109A93: load (dictionary.c:86)
==75771== by 0x1092DB: main (speller.c:40)
==75771==
==75771== LEAK SUMMARY:
==75771== definitely lost: 0 bytes in 0 blocks
==75771== indirectly lost: 0 bytes in 0 blocks
==75771== possibly lost: 0 bytes in 0 blocks
==75771== still reachable: 7,703,248 bytes in 137,558 blocks
==75771== suppressed: 0 bytes in 0 blocks
==75771==
==75771== For lists of detected and suppressed errors, rerun with: -s
==75771== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
// Implements a dictionary's functionality
#include <ctype.h>
#include <stdbool.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <stdio.h>
#include "dictionary.h"
//Declare variables
int word_count;
unsigned int hash_value;
// 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
const unsigned int N = 26;
// Hash table
node *table[N];
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
//Obtain hash value of word
hash_value = hash(word);
//Declare cursor variable
node *cursor = table[hash_value];
while (cursor != 0)
{
//Return true if match found
if (strcasecmp(word, cursor->word) == 0)
{
return true;
}
//Move cursor to next node if no match found
cursor = cursor->next;
}
//Return false if no match after traversing thus misspelt word
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
long sum = 0;
int hash;
//Division hash
for (int i=0; i<strlen(word); i++)
{
sum += tolower(word[i]);
}
hash = sum % N;
return hash;
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
//Open dictionary using fopen r
FILE *source = fopen(dictionary, "r");
if (source == NULL)
{
printf("Error in opening file %s\n", dictionary);
return false;
}
//Declare word variable to store word while scanning
char word[LENGTH + 1];
//Loop to scan for word until fscanf returns EOF
while (fscanf(source, "%s", word) != EOF)
{
//Allocate memory for word node
node *word_node = malloc(sizeof(node));
if (word_node == NULL)
{
return false;
}
//Copy word from source into node
strcpy(word_node->word, word);
//Obtain hash value for word
hash_value = hash(word);
//Insert word into respective hash table
word_node->next = table[hash_value];
table[hash_value] = word_node;
word_count++;
}
//Close file
fclose(source);
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
if (word_count > 0)
{
return word_count;
}
else
{
return 0;
}
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
//Loop through buckets
for (int i = 0; i < N; i++)
{
//point cursor to first table
node *cursor = table[i];
//move cursor until it reaches the end
while (cursor != NULL)
{
//create unloader for current cursor position
node *unloader = cursor;
//move cursor to next node
cursor = cursor->next;
//free memory from current node using unloader
free(unloader);
}
return true;
}
return false;
}