0

I cannot get my dictionaries to load and cannot figure out why. Here is my load function:

// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
    // Opens dictionary and reads
    FILE* dict = fopen(dictionary, "r");
    {
        char newword[46];
        //Returns false if dictionary does not open
        if (!dict)
        {
            return false;
        }
        //Loops through the file as long as it doesn't reach EOF
        while((fscanf(dict, "%s", newword) != EOF))
        {
                //creates an int variable for the int returned from the hash function
                unsigned int x = hash(newword);
                //allocates memory for a new node n and checks to see if there is enough memory
                node *n = malloc(sizeof(node));
                if(n == NULL)
                {
                    return false;
                }
                //copies the current word into the word index of the n node struct
                strcpy (n->word, newword);
                {
                    return 0;
                }
                n->next = NULL;
                //inserting into hash table, new node into linked list
                if(x != N)
                {
                    table[x]->next = n;
                    n->next = NULL;
                    total++;
                }
                else
                {
                    n->next = table[x];
                    table[x]->next = n;
                }
                total++;
        }
    }
    return true;
    return total;
    fclose(dict);
}

I found someone with the same issue as me and similar code and they allocated memory for a new node if x != n (bucket number is non existent). So I attempted this in the code below just as he did it but it did not work although our code is pretty similar. I added the whole code just in case.

// Implements a dictionary's functionality
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
#include <strings.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 = 676;

//Initializes t outside the functions to be accessible in all functions
int total = 0;

// Hash table
node *table[N];

// Returns true if word is in dictionary else false
bool check(const char *word)
{
    // TODO
    unsigned int y = hash(word);
    node *cursor = table[y];
    int match;

    //
    while(cursor != NULL)
    {
        char *word2 = cursor->word;
        //
        match = strcasecmp(word,word2);
        if(match == 0)
        {
            return true;
        }
        else
        {
            cursor = cursor->next;
            word++;
        }
    }
    return false;
}

//hash function sourced and adapted from https://twpower.github.io/160-hash-table-implementation-in-cpp-en
// Hashes word to a number
unsigned int hash(const char *word)
{
    //creates a hash seed value of 401 then loops through the words until NUL
    int hash = 401;
    while (*word != '\0')
    {
        //shifts hash 4bits left (multiplies by 16)
        //takes the int value of the char and converts it to uppercase
        //changing % table[N]
        hash = ((hash << 4) + toupper((int)(*word))) % N;
        word++;
    }

    return hash;
}

// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{
    // Opens dictionary and reads
    FILE* dict = fopen(dictionary, "r");
    {
        char newword[46];
        //Returns false if dictionary does not open
        if (!dict)
        {
            return false;
        }
        //Loops through the file as long as it doesn't reach EOF
        while((fscanf(dict, "%s", newword) != EOF))
        {
                //creates an int variable for the int returned from the hash function
                unsigned int x = hash(newword);
                //allocates memory for a new node n and checks to see if there is enough memory
                node *n = malloc(sizeof(node));
                if(n == NULL)
                {
                    return false;
                }
                //copies the current word into the word index of the n node struct
                strcpy (n->word, newword);
                {
                    return 0;
                }
                n->next = NULL;
                //inserting into hash table, new node into linked list
                if(table[x] == NULL)
                {
                    table[x] = malloc(sizeof(node));
                    table[x] = n;
                    total++;
                }
                else
                {
                    n->next = table[x];
                    table[x]->next = n;
                }
                total++;
        }
    }
    return true;
    return total;
    fclose(dict);
}

// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
    // returns the unsigned int total from load function
    //cannot figure out how to access total from
    return total;
}

// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{
    for(int i = 0; i < N - 1; i++)
    {
        node *cursor = malloc(sizeof(node));
        while(cursor->next != NULL)
        {
            cursor->next = table[N - 1];
            node *temp = malloc(sizeof(node));
            temp = cursor;
            cursor = cursor->next;
            free(&temp);
        }
        free(&cursor);
        return true;
    }
    return false;
}

Update: no longer receive load error but segmentation fault and have no idea why. Here are my Valgrind results

==207== Memcheck, a memory error detector
==207== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==207== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==207== Command: ./speller texts/cat.txt
==207== 
==207== Invalid write of size 8
==207==    at 0x401217: load (dictionary.c:102)
==207==    by 0x400964: main (speller.c:40)
==207==  Address 0x30 is not stack'd, malloc'd or (recently) free'd
==207== 
==207== 
==207== Process terminating with default action of signal 11 (SIGSEGV)
==207==  Access not within mapped region at address 0x30
==207==    at 0x401217: load (dictionary.c:102)
==207==    by 0x400964: main (speller.c:40)
==207==  If you believe this happened as a result of a stack
==207==  overflow in your program's main thread (unlikely but
==207==  possible), you can try to increase the size of the
==207==  main thread stack using the --main-stacksize= flag.
==207==  The main thread stack size used in this run was 8388608.
==207== 
==207== HEAP SUMMARY:
==207==     in use at exit: 608 bytes in 2 blocks
==207==   total heap usage: 3 allocs, 1 frees, 4,704 bytes allocated
==207== 
==207== 56 bytes in 1 blocks are still reachable in loss record 1 of 2
==207==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==207==    by 0x4011C3: load (dictionary.c:91)
==207==    by 0x400964: main (speller.c:40)
==207== 
==207== 552 bytes in 1 blocks are still reachable in loss record 2 of 2
==207==    at 0x4C2FB0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==207==    by 0x5258E49: __fopen_internal (iofopen.c:65)
==207==    by 0x5258E49: fopen@@GLIBC_2.2.5 (iofopen.c:89)
==207==    by 0x40116E: load (dictionary.c:77)
==207==    by 0x400964: main (speller.c:40)
==207== 
==207== LEAK SUMMARY:
==207==    definitely lost: 0 bytes in 0 blocks
==207==    indirectly lost: 0 bytes in 0 blocks
==207==      possibly lost: 0 bytes in 0 blocks
==207==    still reachable: 608 bytes in 2 blocks
==207==         suppressed: 0 bytes in 0 blocks
==207== 
==207== For counts of detected and suppressed errors, rerun with: -v
==207== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault
8
  • 1
    return ends the function. Find the place in the load function that returns way too early! – DinoCoderSaurus Jul 25 '20 at 16:34
  • I got rid of the return 0 under strcpy and now I no longer get a loading error but I get a segmentation fault. Couldn't remember what this was exactly so I looked it up and it said "Core Dump/Segmentation fault is a specific kind of error caused by accessing memory that 'does not belong to you.' When a piece of code tries to do read and write operation in a read only location in memory or freed block of memory, it is known as core dump. It is an error indicating memory corruption." This made me think that maybe the issue was because fopen is set to read rather than w or a but I saw others use – ayeeitsalpha Jul 25 '20 at 21:09
  • read in the code so I thought maybe it had something to do with my memory allocation but comparing to other code it looks fine to me. I thought maybe it was my unload function so I tried to used debug50 and I do not see the execution in the notes or remember how to use it correctly because when I tried it said that no such file existed. – ayeeitsalpha Jul 25 '20 at 21:11
  • I just realized I tried Valgrind before implementing your suggestion so I attempted it again and it worked but I am not sure what to look for exactly. I think the issue is either that the address 0x30 isn't malloc'd or free'd, or that in exit I am still using 608 bytes. I am just not sure how to find that address if it is the issue. I will post the valgrind results to my code if I cannot get it to format correctly/fit in the comments. – ayeeitsalpha Jul 25 '20 at 23:26
  • It is important to know which line gives the seg fault, and it is unlikely that valgrind will help with that. Use this as a guide to help you through debug50. Once the line is found, it will either be evident to you what is the problem, or it will be a new question. This specific question is asked and answered. – DinoCoderSaurus Jul 27 '20 at 13:12

You must log in to answer this question.

Browse other questions tagged .