0

I think I am almost finished with my speller program. It does print out misspelled words correctly, but it doesn't pass the check50, as the size function returns incorrect dictionary size. It fails all of the tests except for one, because the size function always returns expected quantity + 1. I am not sure where it gets this word from. The check for the maximum length work passes, which should give me a clue but it doesn't.

So, for the large dictionary size it should give me 143,091, but I get 143,092.

Can anybody please point me in the right direction?

Please see the code below:

// Implements a dictionary's functionality

#include <stdbool.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#include "dictionary.h"

void delete(treenode* del) {

    if (!del)
        return;

    for (int i = 0; i < 27; i++) {
        delete(del->letters[i]);
    }

    free(del);

}

unsigned int wordcounter;

// Returns true if word is in dictionary else false
bool check(const char *word)
{

    treenode *check = root;

    for (int i = 0; i < strlen(word); i++) {

        int index;

        if (word[i] == '\'') {
            index = 26;
        } else {
            index = tolower(word[i]) - 'a';
        }

        if (check->letters[index] == NULL) {
            return false;
        } else {
            check = check->letters[index];
        }

        if (i == (strlen(word) - 1)) {

            if (check->is_word == false) {
                return false;
            }

        }

    }

    return true;

}

// Loads dictionary into memory, returning true if successful else false
bool load(const char *dictionary)
{

    wordcounter = 0;

    root = malloc(sizeof(treenode));

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

    if (!dict) {
        printf("Could not open dictionary file\n");
        return 1;
    }

    char word[46] = {0};

    while (1) {

        fgets(word, (LENGTH + 1), dict);

        treenode *insert = root;

        for (int i = 0; i < strlen(word); i++) {

            int index = -1;

            if (word[i] == '\'') {
                index = 26;
            } else if (word[i] >= 'a' && word[i] <= 'z') {
                index = tolower(word[i]) - 'a';
            }

            if (index != -1) {

                if (insert->letters[index] == NULL) {
                    insert->letters[index] = (treenode *)malloc(sizeof(treenode));

                    if(!insert->letters[index]) {
                        printf("Error allocating space for new node\n");
                        return 1;
                    }

                    insert = insert->letters[index];
                    for (int j = 0; j < 27; j++) {
                        insert->letters[j] = NULL;
                    }
                } else {
                    insert = insert->letters[index];
                }

            }

            if (i == (strlen(word) - 1)) {
                insert->is_word = true;

                if (root != insert && strlen(word) > 0) {
                    wordcounter++;
                }

            }

        }

        if (feof(dict))
            break;
    }
    fclose(dict);
    return true;
}

// Returns number of words in dictionary if loaded else 0 if not yet loaded
unsigned int size(void)
{
    if (wordcounter >= 1)
        return wordcounter;

    return 0;

}

// Unloads dictionary from memory, returning true if successful else false
bool unload(void)
{

    delete(root);
    return true;
}
1

feof(dict) should be tested after a read operation (fgets), as it reports EOF only after a failed read, which means you insert your last word twice.

Or, read in the condition of your while loop, like while (fgets(word, sizeof(word), dict)). fgets returns the pointer (word in this case) on success, and NULL on failure or EOF.

You seem to set the letters pointer array to all NULL after allocation, which is good. Have you thought about the initial value of is_word?

| improve this answer | |
  • Thank you very much, this is very helpful. I have added insert->is_word = false to my loop. Valgrind was showing some errors, I had to create the same loop for the root node as well, as these values were not initialised. I also moved the feof(dict) check just after the fgets function just like you said and it works perfectly :) – fejkens Sep 28 '18 at 18:17
  • Since NULL and false both are represented by all bytes zero, you could use calloc instead of malloc. It allocates the memory and additionally overwrites it with all zeroes. Or put your allocation and initialisation stuff in a function returning a new and initialised node, so you have it in one place you call from multiple lines. DRY. – Blauelf Sep 29 '18 at 12:21

You must log in to answer this question.

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