-1

I was trying to make a spell checker program where I first have to load a dictionary into memory. To do so, I tried using a hash table. The program shows a segmentation fault when I use the hash function for the hash table.

// Implements a dictionary's functionality

#include <stdbool.h>
#include <errno.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
const unsigned int N = 6536;

// Hash table
node *table[N];

// Returns true if word is in dictionary, else false
bool check(const char *word)
{
    //TODO
    return false;
}

// Hashes word to a number
unsigned int hash(const char *word)         //Hashed using djb2
{
    unsigned long hash = 5381; 
    int c = 0;
   
    while (c == *word++)
    {
        hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
    }
    return hash;
}

// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
    char *str = NULL;
    FILE *dict = fopen(dictionary,"r");
    node *temp = NULL;
    if(dict == NULL)
    {
        //printf("Error: \n", strerror(errno));
        return false;
    }
    for(int i = 0; i < N; i++)
    {
        table[i] = NULL;
    }
    while(fscanf(dict, "%s", str) != 1)
    {
        unsigned int key = hash(str);
        temp = malloc(sizeof(node));
        if(temp == NULL)
        {
            return false;
        }
        if(table[key] != NULL)
        {
            temp->next = table[key]->next;
            strcpy(temp->word, str);
            table[key]->next = temp;
            free(temp);
        }
        else
        {
            table[key] = malloc(sizeof(node));
            table[key]->next = NULL;
            strcpy(table[key]->word, str);
        }
    }
    fclose(dict);
    printf("SUCCESS\n");
    return true;
}

The debugger shows the seg. fault occuring at unsigned int key = hash(str);. I'd like to know how this can be fixed.

MelPradeep
  • 35
  • 5
  • 2
    Why nobody ever posts a [mcve]? – Costantino Grana Jan 23 '21 at 11:34
  • 2
    The loop statement `while (c == *word++)` smells very fishy. Did you mean `while (c = *word++)`? Otherwise, the value of `c` will never be anything other than zero. – Adrian Mole Jan 23 '21 at 11:34
  • @AdrianMole Using `while (c = *word++)` gives a compiler error: `dictionary.c:38:14: note: use '==' to turn this assignment into an equality comparison while (c = *word++)` – MelPradeep Jan 23 '21 at 11:38
  • `while(fscanf(dict, "%s", str) != 1)` -- I'm pretty sure you mean `== 1` here ("as long as scanning a word is successful ...") – M Oehm Jan 23 '21 at 11:39
  • @MOehm That seems to have resolved it! Was `while (c == *word++)` wrong? – MelPradeep Jan 23 '21 at 11:42
  • 1
    Using an assignment as the condition in a `while` loop is allowed and sometimes useful: The assignment produces a values, namely that of the right hand side, and evaluates it as boolean: 0 means false, everything else means true. It is more common to see a comparison with `==` as condition and it is very common to use ans assignment when a comparison is needed. Therefore, the compier issues a warning. You can avoid this warning by plaing the assignment in brackets: `while ((c = *word++)) ...`. – M Oehm Jan 23 '21 at 11:47
  • It is clear that you need an assignment here, otherwise `c` would never change. You are basically saying: Let `c` be the next character in `word`. If it is not the null caracter, enter the loop body. – M Oehm Jan 23 '21 at 11:48

1 Answers1

1

Try

char str[MAX_LEN];

instead of

char *str = NULL;

(after defining MAX_LEN as appopriate for your application).

As M Oehm pointed out in a comment, I think you might be interpreting the return value of fscanf() incorrectly also.

David Collins
  • 2,852
  • 9
  • 13
  • Is there a difference between declaring a character array versus a character pointer when trying to store a string? – MelPradeep Jan 23 '21 at 11:47
  • 1
    Of course there is a difference. The array has already storage for `MAX_LEN` characters attached. The null pointer doesn't have memory attached and cannot be dereferenced. Trying to store data via this pointer will not work and likely crash. – M Oehm Jan 23 '21 at 11:51
  • @MelPradeep What @M Oehm said ;). – David Collins Jan 23 '21 at 11:52