c - 从文件错误中读取单词

标签 c file tree binary-tree

我在从文件中读取单词并将其传递给二叉树时遇到了问题。当我调试它时,它说:

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

这是源代码:

#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;
}

最佳答案

你的程序有几个问题:

  • 在函数中 zero , 你释放指针太早了,你应该移动 free(aTree);作为最后一条语句,否则你会调用未定义的行为,可能是崩溃(但不是你所拥有的,因为你从未调用过这个函数):

    void zero(Tree *aTree) {
        if (aTree != NULL) {
            zero(aTree->left);
            zero(aTree->right);    
            free(aTree);
    }
    
  • 在函数中 alpha ,您在简单循环就足够的地方使用递归。编译器可能会将其转换为循环,但它确实必须这样做。这不是错误,但为什么不使用更惯用的方法,例如:

    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;
        }
    }
    
  • 在函数中 create ,你为字符串分配了一个字节,这绝对是崩溃的原因。你应该分配 strlen(word) + 1或使用 strdup(word) .您不应该转换 malloc() 的返回值要么:

    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;
    }
    
  • 在函数中 insert你打电话alpha多次,这是低效的:你可以使用 switch声明:

    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;
    }
    
  • 函数 main有多个问题:

    • 你不检查是否argv[1]提供给程序。它将是 NULL如果程序在没有命令行参数的情况下运行。
    • 您对文件结尾的测试不正确:temp应定义为 int你应该在用 getc() 从文件中读取字节后测试它的值, 命名为 c 是惯用的用于此的变量。
    • 您应该使用字 rune 字而不是硬编码的 ASCII 值。
    • 测试if (c >= 'A' && c <= 'Z')将适用于 ASCII,这在今天几乎是通用的,但使用 isupper(c) 更可靠相反。
    • 您不需要清除 buffer , 设置 '\0'在最后插入单词之前就足够了。
    • 您还应该检查缓冲区溢出并拒绝处理超过 255 个字符的单词。
    • 你不应该调用 fclose(fp)什么时候fpNULL ,这是未定义的行为。

    这是更正后的版本:

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

关于c - 从文件错误中读取单词,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34964047/

相关文章:

c - 打印 for 循环迭代的最终值

C do-while 循环

c - 从c中的文件中读取多行(不同长度)

java - 如何在 Java 中搜索子文件夹并用新数据重新绘制 jTable?

haskell - 声明 Eq (Tree a) 的实例,其中如果两棵树具有相同的元素,则它们相等

algorithm - 哈夫曼树 : card guessing game

c - "trace_module_put/trace_module_get"实现了什么?

c - 用一个头文件链接多个c文件

file - 无法覆盖文件内容

c - 什么是十进制搜索树?