jesal
jesal

Reputation: 118

Segmentation fault in C when trying to load dictionary into memory (cs50 pset5, speller)

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

Answers (1)

Boris Lipschitz
Boris Lipschitz

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

Related Questions