I've got a problem with pset5 speller leaking memory. If I free that memory, it breaks my program when the check function is called with invalid reads of free'd memory. As you can see from my valgrind output before this is happening on dictionary.c:57, so char* w = malloc(sizeof(word));
If I call free(w) at the end of each iteration of the for loop in the load function, it breaks the program when check is called.
> ==2835==
> ==2835== HEAP SUMMARY:
> ==2835== in use at exit: 6,439,095 bytes in 143,091 blocks
> ==2835== total heap usage: 286,184 allocs, 286,184 frees, 8,729,687 bytes allocated
> ==2835==
> ==2835== 45 bytes in 1 blocks are still reachable in loss record 1 of 2
> ==2835== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
> ==2835== by 0x422A0D: load (dictionary.c:57)
> ==2835== by 0x4209F2: main (speller.c:40)
> ==2835==
> ==2835== 6,439,050 bytes in 143,090 blocks are definitely lost in loss record 2 of 2
> ==2835== at 0x4C2AB80: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
> ==2835== by 0x422A0D: load (dictionary.c:57)
> ==2835== by 0x4209F2: main (speller.c:40)
> ==2835==
> ==2835== LEAK SUMMARY:
> ==2835== definitely lost: 6,439,050 bytes in 143,090 blocks
> ==2835== indirectly lost: 0 bytes in 0 blocks
> ==2835== possibly lost: 0 bytes in 0 blocks
> ==2835== still reachable: 45 bytes in 1 blocks
> ==2835== suppressed: 0 bytes in 0 blocks
> ==2835==
code:
// Implements a dictionary's functionality
#include <stdbool.h>
#include "dictionary.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <cs50.h>
#include <ctype.h>
typedef struct node
{
char* w;
struct node* next;
} node;
int loadedCount;
node* arr[26];
int hash(const char* word);
// Returns true if word is in dictionary else false
bool check(const char* word)
{
// TODO
char tmp[strlen(word) + 1];
strcpy(tmp, word);
for (int i = 0; i < strlen(tmp); i++)
{
tmp[i] = tolower(tmp[i]);
}
int index = hash(tmp);
node* n = arr[index];
while (n != NULL)
{
if (strcmp(n->w, tmp) == 0)
{
return true;
}
n = n->next;
}
return false;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
// TODO
FILE* fp = fopen(dictionary, "r");
char word[45];
while (fscanf(fp, "%s", word) != EOF)
{
char* w = malloc(sizeof(word));
strncpy(w, word, sizeof(word));
int index = hash(word);
node* n = malloc(sizeof(node));
n->w = NULL;
n->next = NULL;
if (arr[index] != NULL)
{
n->next = arr[index];
}
n->w = w;
arr[index] = n;
loadedCount++;
}
fclose(fp);
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
// TODO
return loadedCount;
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
// TODO
for (int i = 0; i < 26; i++)
{
node* n = arr[i];
node* tmp = NULL;
while (n != NULL)
{
tmp = n;
n = n->next;
free(tmp);
}
}
return true;
}
int hash(const char* word)
{
int n = word[0] - 'a';
return n;
}