sorry that this is a repost of a deleted question. I made a mistake in reading the specifications and didn't realise I wasn't able to alter the function declarations in dictionary.c & .h. The response I got in the initial question was a bit disheartening for a beginner, but I made the fixes and am posting the adjusted code. The issue I am having is related to my memory management. I have passed all other criteria on check50, but I can't seem to fix my memory leaks. There is one change I am aware I need, which is to use fclose on the dictionary file. When I do however, it actually causes further issues on check50. I'm having trouble acting on the information Valgrind offers, though I will paste it below.
I'm really not claiming to be incredible at this, so please forgive any mistakes. I had to adjust the code a little after the mistake with the declarations, so apologies if anything of that is left over.
EDIT: I've also just pasted my valgrind report after including fclose(dict); at the very end of the load function (right before return true;).
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <stdlib.h>
#include <ctype.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char input[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table
const unsigned int N = 20000;
int dictsize;
node *memory;
unsigned int code;
// Hash table
node *table[N];
// Returns true if word is in dictionary else false
bool check(const char *word)
{
//obtains hash
code = hash(word);
if (table[code] == NULL)
{
return false;
}
// goes to requested address in hash table
node *tmp = table[code];
// checks for null and iterates along linked list for match
while (tmp != NULL)
{
if (strcasecmp(tmp->input, word) == 0)
{
return true;
}
tmp = tmp->next;
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
unsigned int h = 0;
unsigned int high = 0;
// copying const char in order to edit local variable only. *temp is delcared to allow program to free memory at end of function, wasn't running without it.
char *hword = malloc(LENGTH + 1);
char *temp = hword;
strcpy(hword, word);
while ( *hword )
{
if(isupper(hword[0]) != 0)
{
hword[0] = tolower(hword[0]);
}
h = ( h << 4 ) + *hword++;
if ( high == (h & 0xF0000000) )
h ^= high >> 24;
h &= ~high;
}
while ( h > 19999 )
{
h = h % 20000;
}
free(temp);
return h;
}
// loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
// open dictionary
FILE *dict = fopen(dictionary, "r");
if (dictionary == NULL)
{
return false;
}
// allocates all needed memory in one go so I can unload quickly
memory = malloc(sizeof(node) * 143093);
// using node n to copy dictionary contents and keeping malloc address to free memory in unload
node *n = memory;
char *word = malloc(sizeof(LENGTH + 1));
// scans dictionary for string
for (int a = 1; fscanf(dict, "%s", word) != EOF; a++)
{
// function to hash and load
if (word != NULL)
{
++n;
code = hash(word);
if (n != NULL)
{
strcpy(n->input, word);
n->next = table[code];
table[code] = n;
dictsize = a;
}
}
}
free(word);
return true;
}
// returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
// returns counter value in load
return dictsize;
}
// unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
free(memory); // free all memory used for nodes at once
return true;
}
Valgrind
==22217== Memcheck, a memory error detector
==22217== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==22217== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==22217== Command: ./speller dictionaries/large texts/austen.txt
==22217==
==22217== Invalid write of size 1
==22217== at 0x5248942: _IO_vfscanf (vfscanf.c:1188)
==22217== by 0x52562E5: __isoc99_fscanf (isoc99_fscanf.c:34)
==22217== by 0x4012D2: load (dictionary.c:115)
==22217== by 0x400964: main (speller.c:40)
==22217== Address 0x55cb2b4 is 0 bytes after a block of size 4 alloc'd
==22217== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22217== by 0x4012AE: load (dictionary.c:112)
==22217== by 0x400964: main (speller.c:40)
==22217==
==22217== Invalid read of size 1
==22217== at 0x4C32E03: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22217== by 0x40113C: hash (dictionary.c:69)
==22217== by 0x4012FB: load (dictionary.c:122)
==22217== by 0x400964: main (speller.c:40)
==22217== Address 0x55cb2b4 is 0 bytes after a block of size 4 alloc'd
==22217== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22217== by 0x4012AE: load (dictionary.c:112)
==22217== by 0x400964: main (speller.c:40)
==22217==
==22217== Invalid read of size 1
==22217== at 0x4C32E03: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22217== by 0x40131F: load (dictionary.c:126)
==22217== by 0x400964: main (speller.c:40)
==22217== Address 0x55cb2b4 is 0 bytes after a block of size 4 alloc'd
==22217== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22217== by 0x4012AE: load (dictionary.c:112)
==22217== by 0x400964: main (speller.c:40)
==22217==
==22217== Invalid write of size 1
==22217== at 0x5246FDD: _IO_vfscanf (vfscanf.c:1103)
==22217== by 0x52562E5: __isoc99_fscanf (isoc99_fscanf.c:34)
==22217== by 0x4012D2: load (dictionary.c:115)
==22217== by 0x400964: main (speller.c:40)
==22217== Address 0x55cb2b4 is 0 bytes after a block of size 4 alloc'd
==22217== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==22217== by 0x4012AE: load (dictionary.c:112)
==22217== by 0x400964: main (speller.c:40)
==22217==
==21347==
==21347== HEAP SUMMARY:
==21347== in use at exit: 552 bytes in 1 blocks
==21347== total heap usage: 268,301 allocs, 268,300 frees, 20,365,056 bytes allocated
==21347==
==21347== 552 bytes in 1 blocks are still reachable in loss record 1 of 1
==21347== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21347== by 0x5258E49: __fopen_internal (iofopen.c:65)
==21347== by 0x5258E49: fopen@@GLIBC_2.2.5 (iofopen.c:89)
==21347== by 0x40126E: load (dictionary.c:100)
==21347== by 0x400964: main (speller.c:40)
==21347==
==21347== LEAK SUMMARY:
==21347== definitely lost: 0 bytes in 0 blocks
==21347== indirectly lost: 0 bytes in 0 blocks
==21347== possibly lost: 0 bytes in 0 blocks
==21347== still reachable: 552 bytes in 1 blocks
==21347== suppressed: 0 bytes in 0 blocks
==21347==
==21347== For counts of detected and suppressed errors, rerun with: -v
==21347== ERROR SUMMARY: 2601087 errors from 4 contexts (suppressed: 0 from 0)
Valgrind with fclose(dict);
==22217== Memcheck, a memory error detector
==22217== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==22217== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==22217== Command: ./speller dictionaries/large texts/austen.txt
==22217== Invalid write of size 1
==21960== at 0x5248942: _IO_vfscanf (vfscanf.c:1188)
==21960== by 0x52562E5: __isoc99_fscanf (isoc99_fscanf.c:34)
==21960== by 0x4012D2: load (dictionary.c:115)
==21960== by 0x400964: main (speller.c:40)
==21960== Address 0x55cb2b4 is 0 bytes after a block of size 4 alloc'd
==21960== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21960== by 0x4012AE: load (dictionary.c:112)
==21960== by 0x400964: main (speller.c:40)
==21960==
==21960== Invalid read of size 1
==21960== at 0x4C32E03: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21960== by 0x40113C: hash (dictionary.c:69)
==21960== by 0x4012FB: load (dictionary.c:122)
==21960== by 0x400964: main (speller.c:40)
==21960== Address 0x55cb2b4 is 0 bytes after a block of size 4 alloc'd
==21960== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21960== by 0x4012AE: load (dictionary.c:112)
==21960== by 0x400964: main (speller.c:40)
==21960==
==21960== Invalid read of size 1
==21960== at 0x4C32E03: strcpy (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21960== by 0x40131F: load (dictionary.c:126)
==21960== by 0x400964: main (speller.c:40)
==21960== Address 0x55cb2b4 is 0 bytes after a block of size 4 alloc'd
==21960== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21960== by 0x4012AE: load (dictionary.c:112)
==21960== by 0x400964: main (speller.c:40)
==21960==
==21960== Invalid write of size 1
==21960== at 0x5246FDD: _IO_vfscanf (vfscanf.c:1103)
==21960== by 0x52562E5: __isoc99_fscanf (isoc99_fscanf.c:34)
==21960== by 0x4012D2: load (dictionary.c:115)
==21960== by 0x400964: main (speller.c:40)
==21960== Address 0x55cb2b4 is 0 bytes after a block of size 4 alloc'd
==21960== at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==21960== by 0x4012AE: load (dictionary.c:112)
==21960== by 0x400964: main (speller.c:40)
==21960==
==21884== HEAP SUMMARY:
==21884== in use at exit: 0 bytes in 0 blocks
==21884== total heap usage: 268,301 allocs, 268,301 frees, 20,365,056 bytes allocated
==21884==
==21884== All heap blocks were freed -- no leaks are possible
==21884==
==21884== For counts of detected and suppressed errors, rerun with: -v
==21884== ERROR SUMMARY: 2601087 errors from 4 contexts (suppressed: 0 from 0)