Pset5 Speller: I'm getting segmentation fault with small dictionary - c

When i used check50, my program was not giving any report as output. So i tried my code with small dictionary and i got a segmentation fault. I think it has do with my unload function
This is my code
// Implements a dictionary's functionality
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <strings.h>
#include <ctype.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table
const unsigned int N = 125;
int word_size = 0;
// Hash table
node *hashtable[N];
// Returns true if word is in dictionary else false
bool check(const char *word)
{
//Convert the word to lowercase
int length = strlen(word);
char copy[length + 1];
for (int i = 0; i < length; i++)
{
copy[i] = tolower(word[i]);
}
copy[length] = '\0';
//Find out the hash value
int hash_value = hash(copy);
node *tmp = hashtable[hash_value];
//Check if word is in dictionary
while(tmp != NULL)
{
if(strcasecmp(tmp->word, copy) == 0)
{
return true;
}
tmp = tmp->next;
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
//It's djb2 hash function
unsigned int hash = 5381;
int c;
while ((c = *word++))
hash = ((hash << 5) + hash) + c;
return hash % N;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
//Initialize all indexs of hastable to NULL
for(int i =0; i < LENGTH + 1; i++)
{
hashtable[i] = NULL;
}
char word[LENGTH +1];
int pos;
FILE *dict = fopen(dictionary,"r");
if(dict == NULL)
{
return false;
}
//Scan every word...I think my problem is in here
while (fscanf(dict, "%s", word) != EOF)
{
word_size++;
int length = strlen(word);
char copy[length + 1];
for (int i = 0; i < length; i++)
{
copy[i] = tolower(word[i]);
}
copy[length] = '\0';
node *new_node = malloc(sizeof(node));
strcpy(new_node->word,copy);
new_node->next = NULL;
//Find the hash value
pos = hash(copy);
//Set the pointer of the new node to index of hashtable
new_node->next = hashtable[pos];
hashtable[pos] = new_node;
}
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
return word_size;
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
node *cursor = NULL;
node* tmp = NULL;
for(int i=0; i < N; i++)
{
while(cursor->next != NULL)
{
tmp = cursor;
cursor = cursor->next;
free(tmp);
}
free(cursor);
}
return true;
}
Can anyone say the write logic if my unload function is wrong. It works fine with large dictionary. I tried but couldn't figure out how to use debug50

In your unload () function you soon define
node *cursor = NULL;
but then, without assigning to cursor any other value, you dereference it:
while ( cursor->next != NULL )
Dereferencing a NULL pointer raises undefined behavior, and it will likely result in a segmentation fault.
The following action is free(cursor); that, with a NULL pointer, is not good as well.

Related

Segmentation fault in CS50 Speller. Why?

I am working on the CS50 pset5 Speller, and I keep getting a segmentation fault error. Debug50 suggests the problem is the line n->next = table[index]; in the implementation of the load function, line 110. I tried to revise but I canĀ“t figure out why it would give error. Here below my code, can anyone please help me?
// Implements a dictionary's functionality
#include <stdbool.h>
#include <strings.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node {
char word[LENGTH + 1];
struct node *next;
} node;
// Number of buckets in hash table
const unsigned int N = 150000;
// Nodes counter
int nodes_counter = 0;
// Hash table
node *table[N];
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
// TODO
int hash_value = hash(word);
node *cursor = malloc(sizeof(node));
if (cursor != NULL)
{
cursor = table[hash_value];
}
if (strcasecmp(cursor->word, word) == 0) // If word is first item in linked list
{
return 0;
}
else // Iterate over the list by moving the cursor
{
while (cursor->next != NULL)
{
if (strcasecmp(cursor->word, word) == 0) // If word is found
{
return 0;
}
else
{
cursor = cursor->next;
}
}
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
// Adaptation of FNV function, source https://www.programmingalgorithms.com/algorithm/fnv-hash/c/
const unsigned int fnv_prime = 0x811C9DC5;
unsigned int hash = 0;
unsigned int i = 0;
for (i = 0; i < strlen(word); i++)
{
hash *= fnv_prime;
hash ^= (*word);
}
return hash;
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
// Open Dictionary File (argv[1] or dictionary?)
FILE *file = fopen(dictionary, "r");
if (file == NULL)
{
printf("Could not open file\n");
return 1;
}
// Read until end of file word by word (store word to read in word = (part of node)?)
char word[LENGTH + 1];
while(fscanf(file, "%s", word) != EOF)
{
// For each word, create a new node
node *n = malloc(sizeof(node));
if (n != NULL)
{
strcpy(n->word, word);
//Omitted to avoid segmentation fault n->next = NULL;
nodes_counter++;
}
else
{
return 2;
}
// Call hash function (input: word --> output: int)
int index = hash(word);
// Insert Node into Hash Table
n->next = table[index];
table[index] = n;
}
return false;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
// Return number of nodes created in Load
if (nodes_counter > 0)
{
return nodes_counter;
}
return 0;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
// TODO
for (int i = 0; i < N; i++)
{
node *cursor = table[i];
while (cursor->next != NULL)
{
node *tmp = cursor;
cursor = cursor->next;
free(tmp);
}
}
return false;
}
There are multiple problems in your code:
node *table[N]; cannot be only be defined as a global object if N is a constant expression. N is defined as a const unsigned int, but N is not a constant expression in C (albeit it is in C++). Your program compiles only because the compiler accepts this as a non portable extension. Either use a macro or an enum.
you overwrite cursor as soon as it is allocated in check(). There is no need to allocate a node in this function.
the hash() function should produce the same hash for words that differ only in case.
the hash() function only uses the first letter in word.
the hash() function can return a hash value >= N.
fscanf(file, "%s", word) should be protected agains buffer overflow.
you do not check if cursor is non null before dereferencing it in unload()
Here is a modified version:
// Implements a dictionary's functionality
#include <ctype.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node {
char word[LENGTH + 1];
struct node *next;
} node;
// Number of buckets in hash table
enum { N = 150000 };
// Nodes counter
int nodes_counter = 0;
// Hash table
node *table[N];
// Returns true if word is in dictionary, else false
bool check(const char *word) {
int hash_value = hash(word);
// Iterate over the list by moving the cursor
for (node *cursor = table[hash_value]; cursor; cursor = cursor->next) {
if (strcasecmp(cursor->word, word) == 0) {
// If word is found
return true;
}
}
// If word is not found
return false;
}
// Hashes word to a number
unsigned int hash(const char *word) {
// Adaptation of FNV function, source https://www.programmingalgorithms.com/algorithm/fnv-hash/c/
unsigned int fnv_prime = 0x811C9DC5;
unsigned int hash = 0;
for (unsigned int i = 0; word[i] != '\0'; i++) {
hash *= fnv_prime;
hash ^= toupper((unsigned char)word[i]);
}
return hash % N;
}
// Loads dictionary into memory, returning true if successful, else a negative error number
int load(const char *dictionary) {
// Open Dictionary File (argv[1] or dictionary?)
FILE *file = fopen(dictionary, "r");
if (file == NULL) {
printf("Could not open file\n");
return -1;
}
// Read until end of file word by word (store word to read in word = (part of node)?)
char word[LENGTH + 1];
char format[10];
// construct the conversion specifier to limit the word size
// read by fscanf()
snprintf(format, sizeof format, "%%%ds", LENGTH);
while (fscanf(file, format, word) == 1) {
// For each word, create a new node
node *n = malloc(sizeof(node));
if (n == NULL) {
fclose(file);
return -2;
}
strcpy(n->word, word);
n->next = NULL;
nodes_counter++;
// Call hash function (input: word --> output: int)
int index = hash(word);
// Insert Node into Hash Table
n->next = table[index];
table[index] = n;
}
fclose(file);
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void) {
// Return number of nodes created in Load
return nodes_counter;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void) {
for (int i = 0; i < N; i++) {
node *cursor = table[i];
table[i] = NULL;
while (cursor != NULL) {
node *tmp = cursor;
cursor = cursor->next;
free(tmp);
}
}
return true;
}

Cs50 pset5 speller segmentation, memory errors

I'm doing the speller program and for the past few days I feel like I'm going in circles, receiving the same problems over and over again. Now, the error is free(): "invalid pointer
Aborted", most likely refering to the hash function, in which I use calloc,yet I can't understand what am I doing wrong there. Most likely there are multiple mistakes in my other functions, so tips regarding them would be very appreciated. I'll post the entire program, so I don't have to send snippets of it later. Completely lost here.
Ok, thanks to Tim Randal's answer the free() error looks fixed, however a segmentation error mentioned previously took his place.
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dictionary.h"
#include <strings.h>
#include <ctype.h>
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table
const unsigned int N = 1000;
// Number of words loaded into the dictionary
int counter = 0;
// Hash table
node *table[N] = {0};
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
size_t len = strlen(word);
char *lower = calloc(len+1, sizeof(char));
for (size_t i = 0; i < len; ++i) {
lower[i] = tolower((unsigned char)word[i]);
}
node *cursor = NULL;
cursor = table[hash(lower)];
while (cursor != NULL)
{
if (strcasecmp(cursor->word,lower) == 0)
{
free(lower);
return true;
}
else
{
cursor = cursor->next;
}
}
free(lower);
return false;
}
// Hashes word to a number
//hash function djb2 by Dan Bernstein
unsigned int hash(const char *word)
{
size_t len = strlen(word);
char *lower = calloc(len+1, sizeof(char));
for (size_t i = 0; i < len; ++i)
{
lower[i] = tolower((unsigned char)word[i]);
}
unsigned long hash = 5381;
int c;
while ((c = *lower++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
free(lower);
if (hash > N)
{
hash = hash % N;
return hash;
}
else
{
return hash;
}
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
char word[LENGTH + 1];
node *new_node = NULL;
node *tmp = NULL;
FILE *file = fopen(dictionary,"r");
if (file == NULL)
{
printf("Could not open file\n");
return false;
}
while(fscanf(file, "%s",word) != EOF)
{
new_node = malloc(sizeof(node));
if (new_node == NULL)
{
printf("Not enough memory!\n");
return false;
}
strcpy(new_node->word,word);
unsigned int index = hash(word);
if(table[index] == NULL)
{
table[index] = new_node;
new_node->next = NULL;
}
else
{
tmp = table[index];
table[index] = new_node;
new_node->next = tmp;
}
counter++;
}
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
return counter;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
const char *word = NULL;
int index = hash(word);
for(node *cursor = table[index]; cursor != NULL;cursor = cursor->next)
{
for(node *tmp = table[index]; tmp != NULL; tmp = tmp->next)
{
free(tmp);
}
free(cursor);
}
return true;
}
Here's one problem. I'm not saying it's the only one.
while ((c = *lower++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
free(lower);
You're freeing a pointer after changing it. You will need to copy lower to another pointer, which gets incremented and tested. The original lower needs to remember the address of the first byte allocated.
char* test = lower;
while ((c = *test++))
hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
free(lower);

cs50 speller problem hash table doesn't seem to form in load function

currently doing the speller problem of cs50 pset5.
I'm having a trouble with forming the hash table and i think it causes a segmentation fault later on when i try to run a function that searches the table.
this is the function that creates the hash table:
bool load(const char *dictionary)
{
FILE *dict = fopen(dictionary, "r"); //opens dictionary file
if (dict == NULL) // if cant be opened loading failed
{
return false;
}
char w[LENGTH + 1]; //buffer (length is the maximum character number
int i = 0; //index within word
while(fscanf(dict, "%s", w) != EOF) // scanning the dictionary for words
{
int x = hash(w); //getting the number of the linked list within the table
node *n = malloc(sizeof(node)); //allocating memory for a new node
if (n == NULL)
{
return false;
}
for (int j = 0; j < strlen(w) + 1; j++) // documenting the word within the new node
{
n->word[i] = w[j];
}
n->next = table[x];
table[x] = n; //new node is the beginning of the linked list
dicsize++;
}
fclose(dict);
return true;
}
my main question is whether my code for forming the table is correct and if not then why
thank you in advance
and this is the entire code:
// Implements a dictionary's functionality
#include <string.h>
#include <strings.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table
const unsigned int N = 26;
int dicsize = 0;
// Hash table
node *table[N];
// Returns true if word is in dictionary, else false
bool check(const char *word)
{
int x = hash(word);
node *cur = table[x];
while(table[x] != NULL)
{
if(strcasecmp(word, cur->word) == 0)
{
return true;
}
if(cur == NULL)
{
return false;
}
cur = cur->next;
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
char temp = tolower(word[0]);
int place = (temp - 97);
return place;
}
// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
FILE *dict = fopen(dictionary, "r"); //opens dictionary file
if (dict == NULL) // if cant be opened loading failed
{
return false;
}
char w[LENGTH + 1]; //buffer
int i = 0; //index within word
while(fscanf(dict, "%s", w) != EOF) // scanning the dictionary for words
{
int x = hash(w); //getting the number of the linked list within the table
node *n = malloc(sizeof(node)); //allocating memory for a new node
if (n == NULL)
{
return false;
}
for (int j = 0; j < strlen(w) + 1; j++) // documenting the word within the new node
{
n->word[i] = w[j];
}
n->next = table[x];
table[x] = n; //new node is the beginning of the linked list
dicsize++;
}
fclose(dict);
return true;
}
// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
printf("%i", dicsize);
return dicsize;
}
// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
// TODO
return false;
}
The likely culprit is
for (int j = 0; j < strlen(w) + 1; j++) // documenting the word within the new node
{
n->word[i] = w[j];
}
As i is not changing inside the loop, instead of copying the string it will dump all the chars into one. The other index should also be j. (as in n->word[j] = w[j];)
It would be better to do this as strcpy anyway.

CS50 Speller (PSET 5) not loading dictionary

I am working through the CS50 Speller problem and facing a problem that when running the program it returns an error of "Could not unload dictionaries/large."
I have looked at other people's solutions and can't for the life of me identify what is going wrong in my program. I am thinking it is in the has function, but have seen this has function in other people's working programs?
Any help would be greatly appreciated.
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of words in dictionary
int word_count = 0;
// 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)
{
unsigned int n = hash(word);
node *cursor = table[n];
while (cursor != NULL)
{
if (strcasecmp(word, cursor -> word) == 0)
{
return true;
}
cursor = cursor -> next;
}
return false;
}
// Hashes word to a number
// Function credit to delipity(staff) on CS50 reddit page
unsigned int hash(const char *word)
{
unsigned int hash_value = 0;
for (int i = 0, n = strlen(word); i < n; i++)
{
hash_value = (hash_value << 2) ^ word[i];
}
return hash_value % N; //N is size of hashtable
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
// Open dictionary and check for memory issue
// Open dictionary file and create word array
FILE *dict = fopen(dictionary, "r");
char word[LENGTH + 1];
// Check for memory issue with dict
if(dict == NULL)
{
printf("Dictionary is null\n");
unload();
return false;
}
// Read string 1 word at a time
while (fscanf(dict, "%s", word) != EOF)
{
node *n = malloc(sizeof(node));
if (n == NULL)
{
return false;
}
strcpy(n -> word, word);
word_count++;
// Index word using hash function
int dict_index = hash(word);
// Insert into hash table if already empty
if (table[dict_index] == NULL)
{
n -> next = NULL;
}
// Insert work as new node if not empyty
else
{
n -> next = table[dict_index];
}
table[dict_index] = n;
}
// Close dictionary file
fclose(dict);
// Indicate success
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
return word_count;
return 0;
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
for (int i = 0; i < N; i++)
{
node *cursor = table[i];
node *tmp = cursor;
while (cursor != NULL)
{
cursor = cursor -> next;
free(tmp);
tmp = cursor;
}
}
return false;
}
bool unload(void)
{
for (int i = 0; i < N; i++)
{
node *cursor = table[i];
while (cursor)
{
node *temp = cursor;
cursor = cursor->next;
free(temp);
}
}
return true;
}
Try this instead for the unload function

Spell checker program, check function speller cs50

This program works as a spell checker, it reads a dictionary file to load into the hash table, then reads another text file that will be read and will check every word if it is in the hash table, if not then it is considered a misspelled word. All of my functions seem to work except for my check function, when I run it the number of misspelled words is always the same as the number of words in text. This was working before but I changed the hash function because this hash function was said to be better to assign the values into unique index, but after changing just the hash function the check function doesn't work anymore.
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node
{
char word[LENGTH + 1];
struct node *next;
}
node;
// Number of buckets in hash table
const unsigned int N = 200000;
// Hash table
node *table[N];
// Returns true if word is in dictionary else false
bool check(const char *word)
{
// TODO
int len = strlen(word);
char copy[len + 1];
// change into lowercase the word
for (int i = 0; i != '\0'; i++)
{
copy[i] = tolower(word[i]);
}
// get the index by using the hash function
int index = hash(copy);
if (table[index] == NULL)
{
return false;
}
node *tmp = table[index];
// check if the word is in the hash table
while (tmp != NULL)
{
if (strcmp(tmp->word, copy) == 0)
{
return true;
}
tmp = tmp->next;
}
return false;
}
// Hashes word to a number
unsigned int hash(const char *word)
{
/* credits to...
*https://www.reddit.com/r/cs50/comments/1x6vc8/pset6_trie_vs_hashtable/
*/
unsigned int hash = 0;
for (int i = 0, n = strlen(word); i < n; i++)
{
hash = (hash << 2) ^ word[i];
}
return hash % N;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
// TODO
char *words = malloc(sizeof(char) * (LENGTH + 1));
if (words == NULL)
{
return 1;
}
// initialize the hash table to NULL
for (int i = 0; i < N; i++)
{
table[i] = NULL;
}
// open dictionary file
FILE *indata = fopen(dictionary, "r");
// 1 character for '\0' and another for '\n' because fgets takes a trailing new line
// when it reads 'man' the value of words will be "man\n\0" so meaning 2 extra characters
while (fgets(words, LENGTH + 2, indata) != NULL)
{
// get the index by using the hash function
int index = hash(words);
// allocate memory for the newNode
node *newNode = malloc(sizeof(node));
if (newNode == NULL)
{
return false;
}
// get rid of the trailing new line from fgets
words[strlen(words) - 1] = '\0';
strcpy(newNode->word, words);
// make the newNode the head of the list
newNode->next = table[index];
table[index] = newNode;
}
// free memory and close the opened file
free(words);
fclose(indata);
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
// TODO
// counter of words loaded
unsigned int counter = 0;
// loop through the hash table
for (int i = 0; i < N; i++)
{
node *tmp = table[i];
while (tmp != NULL)
{
counter++;
tmp = tmp->next;
}
}
return counter;
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
// TODO
// loop through the whole hash table
for (int i = 0; i < N; i++)
{
while (table[i] != NULL)
{
node *tmp = table[i]->next;
free(table[i]);
table[i] = tmp;
}
}
return true;
}
There are multiple problems in your code:
The definition node *table[N]; is invalid in C because N must be a compile time constant expression. const unsigned int N = 200000; fits this constraint in C++, but not in C. N must be a macro or an enum definition.
in check(), the loop to copy the string as lowercase is incorrect: for (int i = 0; i != '\0'; i++) should be for (int i = 0; word[i] != '\0'; i++)
in check() you do not null terminate the string you build in copy. copy is allocated with malloc(), it is uninitialized, so the null terminator must be set explicitly.
the char argument in tolower(word[i]) must be cast as tolower((unsigned char)word[i]) to avoid undefined behavior on negative char values, should the char be signed on your platform.
in load(), the words array is allocated with a length of LENGTH+1 bytes, but you pass LENGTH+2 to fgets as the buffer size, causing potential undefined behavior if the dictionary contains a line with LENGTH characters.
in load(), hash(words) is called before stripping the newline at the end of the line. Hence the hash code is incorrect and the word will not be found in the dictionary because it is stored in the wrong bucket.
Here is a modified version:
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include "dictionary.h"
// Represents a node in a hash table
typedef struct node {
struct node *next;
char word[LENGTH + 1];
} node;
// Number of buckets in hash table
#define HASH_SIZE 200000
// Hash table
node *table[HASH_SIZE];
// Hashes word to a number
unsigned int hash(const char *word) {
/* credits to...
*https://www.reddit.com/r/cs50/comments/1x6vc8/pset6_trie_vs_hashtable/
*/
unsigned int hash = 0;
for (int i = 0; word[i] != '\0'; i++) {
hash = (hash << 2) ^ word[i];
}
return hash % HASH_SIZE;
}
// Returns true if word is in dictionary else false
bool check(const char *word) {
char copy[LENGTH + 1];
int i, len = strlen(word);
if (len > LENGTH)
return false;
// change into lowercase the word
for (i = 0; word[i] != '\0'; i++) {
copy[i] = (char)tolower((unsigned char)word[i]);
}
copy[i] = '\0';
// get the index by using the hash function
int index = hash(copy);
// check if the word is in the hash table
for (node *tmp = table[index]; tmp != NULL; tmp = tmp->next) {
if (strcmp(tmp->word, copy) == 0) {
return true;
}
}
return false;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary) {
// 1 character for '\0' and another for '\n' because fgets takes a trailing new line
// when it reads 'man' the value of words will be "man\n\0" so meaning 2 extra bytes
char words[LENGTH + 2];
// open dictionary file
FILE *indata = fopen(dictionary, "r");
if (indata == NULL)
return false;
while (fgets(words, sizeof words, indata) != NULL) {
// get rid of the trailing new line from fgets
words[strcspn(words, "\n")] = '\0';
// allocate memory for the newNode
node *newNode = malloc(sizeof(node));
if (newNode == NULL) {
fclose(indata);
return false;
}
strcpy(newNode->word, words);
// get the index by using the hash function
int index = hash(words);
// make the newNode the head of the list
newNode->next = table[index];
table[index] = newNode;
}
// close the opened file
fclose(indata);
return true;
}
// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void) {
// counter of words loaded
unsigned int counter = 0;
// loop through the hash table
for (int i = 0; i < HASH_SIZE; i++) {
for (node *tmp = table[i]; tmp != NULL; tmp = tmp->next) {
counter++;
}
}
return counter;
}
// Unloads dictionary from memory, returning true if successful else false
bool unload(void) {
// loop through the whole hash table
for (int i = 0; i < HASH_SIZE; i++) {
while (table[i] != NULL) {
node *next = table[i]->next;
free(table[i]);
table[i] = next;
}
}
return true;
}

Resources