简体   繁体   中英

Reading words from file error

I've got a problem with reading words from file and passing it to binary tree. When I debug it, it says:

Unhandled exception at 0x76E7773B(ntdll.dll) in Projekt.exe: 0.C00000005:
    Access violation reading location 0x0037902A.

Here is the source code:

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

typedef struct Tree {
    int val;
    char *word;
    struct Tree *left;
    struct Tree *right;
} Tree;

void show(Tree *hd) {
    if (hd != NULL) {
        show(hd->left);
        show(hd->right);
        printf("%s -- %d\n", hd->word, hd->val);
    }
}

void zero(Tree *aTree) {
    if (aTree == NULL)
        return;

    zero(aTree->left);
    free(aTree);
    zero(aTree->right);    
}

int alpha(char *word1, char *word2) {
    if (word1[0] == 0 && word2[0] == 0)
        return 2;
    else
    if (word1[0] == word2[0])
        return alpha(&word1[1], &word2[1]);
    else
    if (word1[0] < word2[0])
        return 1;
    else
        return 0;
}

Tree *create(char *word) {
    Tree *temp;
    temp = (Tree*)malloc(sizeof(Tree));
    temp->left = temp->right =  NULL;
    temp->val = 1;
    temp->word = (char*)malloc(sizeof(char));
    strcpy(temp->word, word);
    return temp;
}

Tree *insert(Tree *aTree, char *word) {
    if (aTree == NULL) {
        aTree = create(word);
    } else
    if (alpha(aTree->word, word) == 0) {
        aTree->left = insert(aTree->left,word);
    } else
    if (alpha(aTree->word, word) == 1) {
        aTree->right = insert(aTree->right, word);
    } else
    if (alpha(aTree->word, word) == 2) {
        aTree->val++;
    }
    return aTree;
}

int main(int argc, char *argv[]) {
    Tree *myTree = NULL;
    char buffer[256] = { 0 };
    char temp = 0;
    int i = 0;
    FILE *fp = fopen(argv[1], "r");
    if (fp)  {
        while (temp != EOF) {
            temp = getc(fp);
            temp = toupper(temp);
            if (temp >= 65 && temp <= 90) {
                buffer[i] = temp;
                i++;
            } else {
                if (buffer[0] != 0) {
                    puts(buffer);
                    myTree = insert(myTree, buffer);
                    memset(buffer, 0, sizeof(buffer));
                    i = 0;
                }
            }
        }
    }
    fclose(fp);
    show(myTree);
    return 0;
}

Your program has several problems:

  • in function zero , you free the pointer too soon, you should move the free(aTree); as the last statement, otherwise you invoke undefined behavior, possibly a crash (but not the one you have, since you never call this function):

     void zero(Tree *aTree) { if (aTree != NULL) { zero(aTree->left); zero(aTree->right); free(aTree); } 
  • In function alpha , you use recursion where a simple loop would suffice. The compiler may convert this to a loop, but it does have to. This is not a bug but why not use a more idiomatic approach such as:

     int alpha(const char *word1, const char *word2) { for (size_t i = 0;; i++) { if (word1[i] == '\\0' && word2[i] == '\\0') return 2; if (word1[i] == word2[i]) continue; if (word1[i] < word2[i]) return 1; else return 0; } } 
  • In function create , you allocate a single byte for the string, this is definitely a cause for the crash. You should allocate strlen(word) + 1 or use strdup(word) . You should not cast the return value of malloc() either:

     Tree *create(const char *word) { Tree *temp; temp = malloc(sizeof(Tree)); temp->left = temp->right = NULL; temp->val = 1; temp->word = strdup(word); return temp; } 
  • In function insert you call alpha multiple times, this is inefficient: you could use a switch statement:

     Tree *insert(Tree *aTree, const char *word) { if (aTree == NULL) { return create(word); switch (alpha(aTree->word, word)) { case 0: aTree->left = insert(aTree->left, word); break; case 1: aTree->right = insert(aTree->right, word); break; case 2: aTree->val++; break; } } return aTree; } 
  • function main has multiple issues:

    • You do not check if argv[1] is provided to the program. It would be NULL if the program is run without a command line argument.
    • Your test for end of file is incorrect: temp should be defined as int and you should test its value after reading the byte from the file with getc() , it is idiomatic to name c a variable used for this.
    • You should use character literals instead of hard coded ASCII values.
    • the test if (c >= 'A' && c <= 'Z') would work for ASCII, which is almost universal today, but it is more reliable to use isupper(c) instead.
    • You do not need to clear the buffer , setting a '\\0' at the end before inserting the word is enough.
    • You should also check for buffer overflow and refuse to handle words longer than 255 characters.
    • You should not call fclose(fp) when fp is NULL , this is undefined behavior.

    Here is a corrected version:

     int main(int argc, char *argv[]) { Tree *myTree = NULL; char buffer[256]; int c; size_t i; FILE *fp; if (argc < 2) { printf("missing argument\\n"); return 2; } fp = fopen(argv[1], "r"); if (fp == NULL) { printf("cannot open %s\\n", argv[1]); return 1; } i = 0; while ((c = getc(fp)) != EOF) { c = toupper(c); if (isupper(c)) { if (i < sizeof(buffer)) buffer[i] = c; i++; } else { if (i > 0 && i < sizeof(buffer)) { buffer[i] = '\\0'; puts(buffer); myTree = insert(myTree, buffer); i = 0; } } } fclose(fp); show(myTree); return 0; } 

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM