0

I would love a bit of help on cs50's pset5 speller. The program does compile. However, when I run valgrind ./speller texts/cat.txt I get a segmentation fault . I think I am overlooking something but I can't figure out what. Could someone please help me identify where the error(s) lies?

// Implements a dictionary's functionality
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include "dictionary.h"
#include <string.h>
#include <ctype.h>
#include <strings.h>

int count = 0;

// 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;

// Hash table
node *table[N];

// Returns true if word is in dictionary, else false
bool check(const char *word)
{
    // TODO
    char *term = NULL;
    strcpy(term, word);
    int array_location = hash(term);
    for(node *find = table[array_location]; find != NULL; find = find->next)
    {
        if (strcasecmp(word, find->word) == 0)
        {
            return true;
        }
    }
    return false;
}


// Hashes word to a number
unsigned int hash(const char *word)
{
    // TODO
    char first_letter = *word;
    char capital_letter = toupper(first_letter);
    int letter_number = atoi(&capital_letter);
    int hash_code = letter_number - 65;
    return hash_code;
}

// Loads dictionary into memory, returning true if successful, else false
bool load(const char *dictionary)
{
    // TODO
    for(int y = 0; y < 26; y++)
    {
        table[y] = NULL;
    }
    FILE *f = fopen("dictionary", "r");
    if (f != NULL)
    {
        char *term = NULL;
        while(fscanf(f, "%s", term) != EOF)
        {
            fscanf(f, "%s", term);
            node *nd = malloc(sizeof(node));
            if (nd != NULL)
            {
                strcpy(nd->word, term);
                int array_location = hash(term);
                if(table[array_location] == NULL)
                {
                    nd->next = NULL;
                    table[array_location] = nd;
                    count++;
                }
                else
                {
                    nd->next = table[array_location];
                    table[array_location] = nd;
                    count++;
                }
            }
            else
            {
                fclose(f);
                return false;
            }
        }
    }
    else if (f == NULL)
    {
        fclose(f);
        return false;
    }
    fclose(f);
    return true;
}

// Returns number of words in dictionary if loaded, else 0 if not yet loaded
unsigned int size(void)
{
    // TODO
    return count;
}

// Unloads dictionary from memory, returning true if successful, else false
bool unload(void)
{
    // TODO
    for(int i = 0; i < 26; i++)
    {
        node *marker = table[i];
        node *deleter = marker;
        while (deleter != NULL)
        {
            marker = marker->next;
            free (deleter);
            deleter = marker;
        }
    }
    return false;
}

The following is what valgrind returns:

==413== Memcheck, a memory error detector
==413== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==413== Using Valgrind-3.15.0 and LibVEX; rerun with -h for copyright info
==413== Command: ./speller texts/cat.txt
==413== 
==413== Invalid read of size 4
==413==    at 0x4A28F5B: fclose@@GLIBC_2.2.5 (iofclose.c:48)
==413==    by 0x401C0D: load (dictionary.c:97)
==413==    by 0x4012CE: main (speller.c:40)
==413==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
==413== 
==413== 
==413== Process terminating with default action of signal 11 (SIGSEGV)
==413==  Access not within mapped region at address 0x0
==413==    at 0x4A28F5B: fclose@@GLIBC_2.2.5 (iofclose.c:48)
==413==    by 0x401C0D: load (dictionary.c:97)
==413==    by 0x4012CE: main (speller.c:40)
==413==  If you believe this happened as a result of a stack
==413==  overflow in your program's main thread (unlikely but
==413==  possible), you can try to increase the size of the
==413==  main thread stack using the --main-stacksize= flag.
==413==  The main thread stack size used in this run was 10485760.
==413== 
==413== HEAP SUMMARY:
==413==     in use at exit: 0 bytes in 0 blocks
==413==   total heap usage: 1 allocs, 1 frees, 472 bytes allocated
==413== 
==413== All heap blocks were freed -- no leaks are possible
==413== 
==413== For lists of detected and suppressed errors, rerun with: -s
==413== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault

1 Answer 1

1

For starters, the program doesn't actually compile without error. It's probably compiling in your environment with a warning about an unused parameter in the call to load().

In most people's environment, that would produce a warning about the unused parameter of dictionary in the signature which would be treated as an error.

The root cause of that is this line:

FILE *f = fopen("dictionary", "r");

By putting dictionary in quotes, you're telling the code to open a file that's literally named "dictionary", and not to use the value in the var dictionary. So, if you remove the quotes, it'll use the actual target file given when speller is invoked.

When the quotes and the program correctly compiled, other problems including a seg fault show up. I'll let you work on them for a while and post a fresh question if you need to. ;-)

If this answers this issue, please click on the check mark to accept. Let's keep up on forum maintenance. ;-)

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .