The following is my code and, subsequently, the message Valgrind returns when I run it on ./speller texts/lalaland.txt.
I explored similar issues previously posted on Stack exchange, and added lines to ensure that I was freeing any memory I had malloc'd. However, the exact same amount of memory continues to leak. Would massively appreciate some guidance on my code.
Thanks!
// Implements a dictionary's functionality
#include <string.h>
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include "dictionary.h"
#include <stdlib.h>
// 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)
{
// TODO
int h = hash(word);
if (table[h]->next != NULL)
{
node *ptr = table[h];
while (ptr -> next != NULL)
{
if (strcmp(word, ptr -> word) == 0)
{
return true;
}
ptr = ptr -> next;
}
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
// TODO: Improve this hash function
int first_letter = word[0];
if(first_letter >= 65 && first_letter <= 90)
{
int hash_number = (first_letter - 65) % 26;
return hash_number;
}
else if(first_letter >= 97 && first_letter <= 122)
{
int hash_number = (first_letter - 97) % 26;
return hash_number;
}
return true;
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
// TODO
FILE *dict = fopen(dictionary, "r");
if (dict == NULL)
{
fclose(dict);
return false;
}
char *word = malloc(46 * sizeof(char));
while(fscanf(dict, "%s", word) != EOF)
{
fscanf(dict, "%s", word);
node *tmp = malloc(sizeof(node));
if (tmp == NULL)
{
free(tmp);
free(word);
return false;
}
strcpy(tmp->word, word);
tmp = table[hash(word)]->next;
table[hash(word)]->next = tmp;
free(word);
free(tmp);
}
free(dict);
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
// TODO
int counter = 0;
for(int i = 0; i < N; i++)
{
if (table[i]->next != NULL)
{
node *ptr = table[i];
if (table[i] != NULL)
{
while (ptr ->next != NULL)
{
node *tmp = ptr->next;
ptr = tmp;
counter++;
}
}
}
}
return counter;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
// TOD
node *ptr = NULL;
for(int i = 0; i < N; i++)
{
ptr = table[i];
while(ptr->next != NULL)
{
free(table[i]);
table[i] = ptr;
}
}
free(ptr);
return true;
}
speller/ $ valgrind ./speller texts/lalaland.txt
==5660== Memcheck, a memory error detector
==5660== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5660== Using Valgrind-3.18.1 and LibVEX; rerun with -h for copyright info
==5660== Command: ./speller texts/lalaland.txt
==5660==
==5660== Invalid read of size 8
==5660== at 0x109AF9: load (dictionary.c:85)
==5660== by 0x1092BB: main (speller.c:40)
==5660== Address 0x30 is not stack'd, malloc'd or (recently) free'd
==5660==
==5660==
==5660== Process terminating with default action of signal 11 (SIGSEGV): dumping core
==5660== Access not within mapped region at address 0x30
==5660== at 0x109AF9: load (dictionary.c:85)
==5660== by 0x1092BB: main (speller.c:40)
==5660== If you believe this happened as a result of a stack
==5660== overflow in your program's main thread (unlikely but
==5660== possible), you can try to increase the size of the
==5660== main thread stack using the --main-stacksize= flag.
==5660== The main thread stack size used in this run was 8388608.
==5660==
==5660== HEAP SUMMARY:
==5660== in use at exit: 4,670 bytes in 4 blocks
==5660== total heap usage: 4 allocs, 0 frees, 4,670 bytes allocated
==5660==
==5660== 46 bytes in 1 blocks are still reachable in loss record 1 of 4
==5660== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==5660== by 0x109A66: load (dictionary.c:72)
==5660== by 0x1092BB: main (speller.c:40)
==5660==
==5660== 56 bytes in 1 blocks are still reachable in loss record 2 of 4
==5660== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==5660== by 0x109AA9: load (dictionary.c:77)
==5660== by 0x1092BB: main (speller.c:40)
==5660==
==5660== 472 bytes in 1 blocks are still reachable in loss record 3 of 4
==5660== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==5660== by 0x49C76CD: __fopen_internal (iofopen.c:65)
==5660== by 0x49C76CD: fopen@@GLIBC_2.2.5 (iofopen.c:86)
==5660== by 0x109A3B: load (dictionary.c:65)
==5660== by 0x1092BB: main (speller.c:40)
==5660==
==5660== 4,096 bytes in 1 blocks are still reachable in loss record 4 of 4
==5660== at 0x4848899: malloc (in /usr/libexec/valgrind/vgpreload_memcheck-amd64-linux.so)
==5660== by 0x49C6C23: _IO_file_doallocate (filedoalloc.c:101)
==5660== by 0x49D5D5F: _IO_doallocbuf (genops.c:347)
==5660== by 0x49D4D5B: _IO_file_underflow@@GLIBC_2.2.5 (fileops.c:485)
==5660== by 0x49D5E15: _IO_default_uflow (genops.c:362)
==5660== by 0x49AB14F: __vfscanf_internal (vfscanf-internal.c:628)
==5660== by 0x49AA29C: __isoc99_fscanf (isoc99_fscanf.c:30)
==5660== by 0x109A80: load (dictionary.c:74)
==5660== by 0x1092BB: main (speller.c:40)
==5660==
==5660== LEAK SUMMARY:
==5660== definitely lost: 0 bytes in 0 blocks
==5660== indirectly lost: 0 bytes in 0 blocks
==5660== possibly lost: 0 bytes in 0 blocks
==5660== still reachable: 4,670 bytes in 4 blocks
==5660== suppressed: 0 bytes in 0 blocks
==5660==
==5660== For lists of detected and suppressed errors, rerun with: -s
==5660== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
/opt/cs50/bin/valgrind: line 11: 5660 Segmentation fault (core dumped) /usr/bin/valgrind $*