Reputation: 118
I've partially completed pset5 of cs50, but every time I try to run my program, I get a segfault for some reason.
In my load
function, I open up the dictionary file and initialize my hash table by calling init_table()
. Then, I use fscanf
to scan the dictionary file, create a node *n
for each word in the dictionary, and copy the word from dict_word
into this node. I then use my hash
function (based on djb2) to store the index of this node's word.
If table[index] == NULL
, then I set both table[index]
and a node called head
equal to node n
, and set the next address equal to NULL
. Otherwise, I set the next node as table[index]
and table[index]
as the current node, n
.
I did not yet free any memory because that will be done in another function called unload
, but I suspect my current problem is likely due to a different reason. Any help would be greatly appreciated.
// Implements a dictionary's functionality
#include <stdbool.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.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 (A-Z)
const unsigned int N = 5381;
// Hash table
node *table[N];
// initialize hash table (set all values to NULL)
// reference video: https://youtu.be/2Ti5yvumFTU
void init_table()
{
for (int i = 0; i < N; i++)
{
table[i] = NULL;
}
}
// Hashes word to a number
// hash function: djb2
// retrieved from http://www.cse.yorku.ca/~oz/hash.html
unsigned int hash(const char *word)
{
unsigned int hash_value = N;
int c;
while ((c = *word++))
{
hash_value = ((hash_value << 5) + hash_value) + c; /* hash * 33 + c */
}
return hash_value;
}
// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
// open dictionary file, check if NULL
FILE *dict_file = fopen(dictionary, "r");
if (dict_file == NULL)
{
return false;
}
init_table();
// create char for each dictionary word (max length + nul)
char dict_word[LENGTH + 1];
// create beginning node that serves as first item in linked list
node *head;
// scan until end of file
while (fscanf(dict_file, "%s", dict_word) != EOF)
{
// create a node n for each word and copy string into it
node *n = malloc(sizeof(node));
if (n == NULL)
{
return false;
}
strcpy(n->word, dict_word);
// hash the word and store as index (which tells which linked list to use)
int index = hash(n->word);
// if table[index] is NULL, set it and head as node n, set next node as NULL
if (table[index] == NULL)
{
head = table[index] = n;
n->next = NULL;
}
// otherwise set next node as table[index], table[index] as current node n
else
{
n->next = head;
table[index] = n;
}
}
return true;
}
EDIT: After reading Boris Lipschitz's answer, I've realized the problem and further learned how to use a debugger to solve it. I modified const unsigned int N = 5381
and changed the value of N
to 25
to represent a bucket for each letter in the alphabet (though I may change this value later to optimize my program). For my hash
function, like Boris stated, there was nothing to prevent hash_value
from going past N
, so I changed return hash_value;
to instead be return hash_value % N;
, which will give me an output that is within the proper bounds of my table.
Upvotes: 0
Views: 708
Reputation: 1641
There is absolutely nothing in your hash
function that prevents it from being 5381 or higher. And then you access table
with it... boom, segmentation fault.
Reverse question: why didn't you just run your code in a debugger? You'd know the answer way quicker than any of us could possibly respond.
Upvotes: 1