我在从文件中读取单词并将其传递给二叉树时遇到了问题。当我调试它时,它说:
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)
什么时候fp
是NULL
,这是未定义的行为。
这是更正后的版本:
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/