I've finally got my speller to work for the large dictionary and the given texts. Valgrind doesn't give any errors anymore. However, check50 fails, because the 'actual output' received there does not match the expected output. When I run speller, the output does match the expected output, which puzzles me. I found out that somehow, speller does not work when I use a small dictionary - it will return a segmentation fault when reading the unload function (line: while(cursor->next != NULL)). I'm puzzled. Any hints, advice or help would be greatly appreciated.
#include <stdbool.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "dictionary.h"
//define node structure to make linked lists possible. A node consist of a dicword (char) and a pointer to another node.
typedef struct node
{
char dicword[LENGTH+1];
struct node *next;
}
node;
//create a hash table (size 2)
#define HASHMAX 32
node *hashtable[HASHMAX];
// hash function by Gabriel Staples: https://stackoverflow.com/questions/7666509/hash-function-for-string
unsigned int hash(const char *str)
{
unsigned hashval;
for (hashval = 0; *str != '\0'; str++)
hashval = *str + 31*hashval;
return hashval % HASHMAX;
}
//create counter for dictionary words
int dicwords = 0;
//CHECK Returns true if word is in dictionary else false.
bool check(const char *word)
{
//hash the word to receive index for hashtable
int index = hash(word);
//input index in hashtable to retrieve the right llist. If the llist is empty, return false.
if(hashtable[index]==NULL)
{
return false;
}
//if llist is not empty, run through list and compare word with each element of that list, untill end of list (null) is reached.
else
{
node *cursor = hashtable[index];
while(cursor != NULL)
{
if(strcasecmp(cursor->dicword, word) ==0)
{
return true;
}
cursor = cursor->next;
}
return false;
}
}
//LOAD Loads dictionary into memory. Returns true if successful else false.
bool load(const char *dictionary)
{
//set values in hash table to null
for(int h = 0; h < HASHMAX; h++)
{
hashtable[h] = NULL;
}
//open dictionary for reading
FILE *dic = fopen(dictionary, "r");
if (dic == NULL)
{
return false;
}
char newword[LENGTH+1];
//scan dictionary (dic) and store each string until space in 'newword'
while (fscanf(dic,"%s", newword)!=EOF)
{
node *new_node = malloc(sizeof(node));
new_node->next=NULL;
//if malloc fails, return false
if(new_node == NULL)
{
unload();
return false;
}
//if malloc works, copy 'newword' to the word-space in the new node
else
{
strcpy(new_node->dicword, newword);
dicwords++;
//allocate the new node to the correct list, using hash(word).
new_node->next=hashtable[hash(newword)];
hashtable[hash(newword)]=new_node;
}
}
fclose(dic);
return true;
}
/**
* Returns number of words in dictionary if loaded else 0 if not yet loaded.
*/
unsigned int size(void)
{
if (dicwords>0)
{
return dicwords;
}
else
{
return 0;
}
}
/**
* Unloads dictionary from memory. Returns true if successful else false.
*/
bool unload(void)
{
for (int u = 0; u<HASHMAX; u++)
{
node *cursor = hashtable[u];
while(cursor->next != NULL)
{
node *temp = cursor;
cursor = cursor->next;
free(temp);
}
free(cursor);
}
return true;
}