0

So I've been testing speller and checked it with the staff solution and get matching outputs (click here for comparison).

But when I run with valgrind every word is mispelled.

valgrind --leak-check=full ./speller texts/ralph.txt
==7550== Memcheck, a memory error detector
==7550== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
==7550== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
==7550== Command: ./speller texts/ralph.txt
==7550== 

MISSPELLED WORDS

When
I
grow
up
I
want
to
be
a
principal
or
a
caterpillar
I
love
you
Principal
Skinner
Ralph
Wiggum

WORDS MISSPELLED:     20
WORDS IN DICTIONARY:  1439228
WORDS IN TEXT:        20
TIME IN load:         3.86
TIME IN check:        0.00
TIME IN size:         0.00
TIME IN unload:       0.00
TIME IN TOTAL:        3.86

==7550== 
==7550== HEAP SUMMARY:
==7550==     in use at exit: 0 bytes in 0 blocks
==7550==   total heap usage: 3 allocs, 3 frees, 1,368 bytes allocated
==7550== 
==7550== All heap blocks were freed -- no leaks are possible
==7550== 
==7550== For counts of detected and suppressed errors, rerun with: -v
==7550== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Clearly, something is going wrong with valgrind. My dictionary size is huge ,but only 3 allocs are detected? So obviously, I can't pass any of the checks either since every word is detected as misspelled.

Can anyone help me figure out why I'm getting this problem?

Here's my full code.

/**
 * Implements a dictionary's functionality.
 */

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


#include "dictionary.h"

// Declare dictionary struct
typedef struct node {
    bool is_word;
    struct node *children[27];
    int size;
}

node;
struct node *root = NULL;
struct node *current = NULL;
bool recursionCheck(int i, const char* word);
bool recursionUnload(node* pointer);
int NODESIZE = sizeof(struct node);

/**
 * Returns true if word is in dictionary else false.
 */
bool check(const char *word)
{
    //cat test
    // if (root->children['c'-97]!=NULL &&
    //     root->children['c'-97]->children['a'-97]!=NULL &&
    //     root->children['c'-97]->children['a'-97]->children['t'-97]!=NULL){
    //         printf("cat is in the dictionary\n");
    //         printf("%d \n", root->children['c'-97]->children['a'-97]->children['t'-97]->is_word);
    //         return true;
    //     }

    // initialize variables
    // printf("incoming word is %s\n", word);
    // printf("the first letter is %c\n", word[0]);
    return recursionCheck(0, word);
}

/**
 * Recursion search function helper
 */

 bool recursionCheck (int i, const char *word){

    char c;
    //printf("%s is %lu letters\n", word, strlen(word));
    //printf("The dictionary size is %i\n", root->size);


    // convert letter to lowercase
    if(word[i]>='A' && word[i]<='Z'){
        c = word[i] + 32;
    } else {
        c = word[i];
    }


    // convert locwercase letter to 0-26
    int loc;

    if (c == '\''){
        loc = 26;
    } else {
        loc = c - 97;
        //printf("%c = %i \n", c, loc );

    }
    // check if child is null aka check if letter exists in dictionary

    if (current->children[loc] == NULL) {
        current = root;
        return false;
    } else {
        // check if end of the word
        if (i==strlen(word)-1) {
            //printf("checking end of word... \n");
            // reset variables
            node *test = current->children[loc];
            current = root;
            //printf("%d \n", test->is_word);
            return test->is_word;
        } else {
            current = current->children[loc];
            i++;
            return recursionCheck(i, word);
        }
    }

}



/**
 * Loads dictionary into memory. Returns true if successful else false.
 */
bool load(const char *dictionary)
{
    // Open File

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

    // check if dictionary can be opened

    if (fp == NULL){
        fprintf(stderr, "Dictionary %s cannot be opened. \n", dictionary);
        return false;
    }

    // declare important variables

    root = calloc(1,NODESIZE);
    root->size =0;
    current = root;
    int reading = 1;
    char C[1];

    while(reading == 1){

        // check if end of file
        if(feof(fp)){
            reading = 0;
            // close files
            fclose(fp);

            // readjust dictionary size;
            root->size--;
            //printf("The dictionary size is %i", root->size);
            current = root;
            return true;

        }

        // read next character
        fread(C, 1, 1, fp);

        // check if end of word
        int end = strcmp(C, "\n");

        if (end == 1){
            // set is_word to true
            current->is_word = true;
            if (current->is_word == true){
                root->size++;

            }
            // reset current
            current = root;
        } else {
            int loc;
            //printf("%s", C);
            if (*C == '\''){
                loc = 26;
            } else {
                loc = *C - 97;
            }


            // create node if child is NULL
            if (current->children[loc] == NULL) {
                current->children[loc] = calloc(1,NODESIZE);
            }

            // update current
            current = current->children[loc];

        }







    }


    fclose(fp);
    return false;
}

/**
 * Returns number of words in dictionary if loaded else 0 if not yet loaded.
 */
unsigned int size(void)
{
    return root->size;
}

/**
 * Unloads dictionary from memory. Returns true if successful else false.
 */
bool unload(void)
{
    return recursionUnload(root);
}

bool recursionUnload(node * pointer){
    // TODO
    for (int i = 0; i <27; i++){
        if (pointer->children[i] != NULL){
            node *temp = pointer->children[i];
            recursionUnload(temp);
        }
    }

    free(pointer);
    return true;
}
1

Got the answer from another person.

int end = strcmp(C, "\n");

    if (end == 1){

From the facebook CS50 group, a person said

The only really big thing i can see is that your strcmp call that checks for the newline is not guaranteed to return true at all because you're not comparing a valid string. Other than that, i can't see anything other than the fact that you're doing things in a bit of a complicated way

So I changed it to

if (*C == '\n'){

And everything works great! No idea why valgrind was outputting what it was though.

3
  • Maybe @kareem can explain WHY this code works on its own but fails when run with valgrind. I had the same experience running your code.
    – Cliff B
    Oct 6 '17 at 8:36
  • It all depends on the byte behind *C. If that one's 0 by coincidence, strcmp would see a one-character string, and everything's fine. If there's something other than zero, strcmp would assume that to be part of the string (strings range up to the next zero byte), and a string "\nArbitraryData" is considered larger than "\n". Not sure why this differs in the two cases. Not sure why this code works in the first place either :P
    – Blauelf
    Oct 10 '17 at 15:42
  • haha I guess it's filed under #mysteriesofC for now. Oct 12 '17 at 3:43

You must log in to answer this question.

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