clinuxgccmemory-leaksgcc-warning

Why am I getting a "Program failed: Memory fault, core dumped" in my C program?


This program reads text from the standard input and builds a binary search tree containing the individual words from the input. The program reads input until no more data is available, counting the frequency of occurrence of each word in the input. Once the input has been exhausted, the tree will be traversed with an in-order traversal to produce an alphabetical list of words with their frequencies.

Problem: I can compile my code without any errors and when I run ./wordFreq < input.1, it runs perfect and outputs the correct answer with no errors...this is the correct output:

additional 1
agree 3
another 3
don't 3
for 1
I 1
input 4
is 3
line 5
need 1
one 1
road 1
the 1
think 1
This 4
we 1
yet 1
you 3

But whenever I submit it to the try server it tests the code and tells me that I didn't output anything, and that I had a "Program failed: Memory fault, core dumped", this is the output I am getting on page 1: Try Submission Output

This is my wordFreq.c file:

#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include "wordFreq.h"

#define UNUSED(p)  ((void)(p))

// Creates a node for each unique word it is given, and then inserts this 
// new node in the proper position in the binary search tree, updating 
// whatever pointer is necessary.
//
// @param root a pointer to the variable which contains the pointer to the       
//               root-level node in the tree
// @param word a pointer to the NUL-terminated arrach of characters
void insert_word(TreeNode** root, const char *word){
    if (*root == NULL){
        *root = (TreeNode*)malloc(sizeof(TreeNode));
        unsigned int len = strlen(word);
        (*root)->word = (char *)malloc((len + 1) * sizeof(char));
        strncpy((*root)->word, word, len);
        (*root)->word[len] = 0;
        (*root)->frequency = 1;
        (*root)->left = NULL;
        (*root)->right = NULL;
    }
    else{
        int compare = strcasecmp(word, (*root)->word);
        if (compare < 0){
            insert_word(&((*root)->left), word);
        } else if(compare> 0){
            insert_word(&((*root)->right), word);
        } else if(compare == 0){
            (*root)->frequency++;
        }
    }
}

// Traverses the entire tree using an in-order traversal and will 
// print th contents of each node as it is visited
//
// @param root a pointer to the root node of the tree
void traverse_tree(const TreeNode* root){
    if (root == NULL)
        return;
    if (root != NULL){
        traverse_tree(root->left);
        printf("%s %d\n", root->word, root->frequency);
        traverse_tree(root->right);
    }
    return;
}

// Deallocates all the nodes that were created in insert_node()
//
// @param a pointer to the root node of the tree
void cleanup_tree(TreeNode* root){
    if (root == NULL)
        return;
    if (root->left != NULL){
        cleanup_tree(root->left);
    }
    if(root->right != NULL){
        cleanup_tree(root->right);
    }   
    free(root->word);
    free(root);
    return;
}

int main(int argc, char* argv[]){
    UNUSED(argv);
    if (argc > 1)
        printf("Usage: bst");
    else{
        FILE* pFile = fopen("input.1", "r");
        char *buf = NULL;
        size_t len = 0;
        TreeNode** root = NULL;
        if (!pFile){
            printf("File not found");
        } else{
            root = (TreeNode**)malloc(sizeof(TreeNode*));
            *root = NULL;
            while (getline(&buf,&len,pFile) > 0){
                char * pch;
                pch = strtok(buf, " !@#$%^&*?.,:;\n");
                while (pch !=NULL){
                    insert_word(root, pch);
                    pch = strtok(NULL, " !@#$%^&*,:;?.\n"); 
                }
            }
            free(buf);
            fclose(pFile);
            traverse_tree(*root);
        }
        cleanup_tree(*root);
        free(root);

    }
    return 0;   
}    

This is my wordFreq.h file:

#ifndef _BST_H_
#define _BST_H_

// The definition of the tree structure
typedef struct TreeNode_st {
    char *word;                   // the word held in this node
    unsigned int frequency;       // how many times it has been seen
    struct TreeNode_st *left;     // node's left child
    struct TreeNode_st *right;    // node's right child
} TreeNode;

// FUNCTIONS ARE REQUIRED TO IMPLEMENT

// insert_word() 
//     Dynamically build BST by allocating nodes from the heap
//
// args -
//        root - a pointer to the pointer to the root of the tree
//               to build this tree on to.
//        word - string containing the word to be inserted

void insert_word( TreeNode** root, const char *word );

// traverse_tree()
//    Recursively traverses the tree and prints the value of each
//    node.
//
// args -
//        root - a pointer to the root of the tree to traverse

void traverse_tree( const TreeNode* root );

// cleanup_tree()
//    Cleanup all memory management associated with the nodes on the heap
//
// args
//      root - the current root of the tree

 void cleanup_tree( TreeNode* root );

 #endif // BST_H

This is the input file (named input.1):

This is one input line.
This is another input line, don't you agree?
Another input line, don't you agree?
This is yet another input line, don't you agree?
I think we need this additional line for the road.

Compile Commands:

root@comp:~/Desktop/Homeworks/5$ gcc -ggdb -std=c99 -Wall -Wextra -pedantic  -c wordFreq.c
root@comp:~/Desktop/Homeworks/5$ gcc -ggdb -std=c99 -Wall -Wextra -pedantic -o wordFreq wordFreq.o  -lm

Valgrind Test: I also tested the code in valgrind using the command:

I got no errors... here's the link to test on page 2: Valgrind Test Link


Solution

  • You have some issues in your code:

    The only serious issue is the second point above, although it is unlikely to explain the observed behavior.