从文件错误中读取单词
Reading words from file error
我在从文件中读取单词并将其传递给二叉树时遇到问题。当我调试它时,它说:
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] == '[=11=]' && word2[i] == '[=11=]')
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()
的 return 值:
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
用于此的变量。
- 您应该使用字符文字而不是硬编码的 ASCII 值。
- 测试
if (c >= 'A' && c <= 'Z')
适用于 ASCII,它在今天几乎是通用的,但使用 isupper(c)
更可靠。
- 不需要清除
buffer
,在插入单词前设置一个'[=35=]'
即可。
- 您还应该检查缓冲区溢出并拒绝处理超过 255 个字符的单词。
- 当
fp
为 NULL
时,您不应调用 fclose(fp)
,这是未定义的行为。
这是更正后的版本:
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] = '[=14=]';
puts(buffer);
myTree = insert(myTree, buffer);
i = 0;
}
}
}
fclose(fp);
show(myTree);
return 0;
}
我在从文件中读取单词并将其传递给二叉树时遇到问题。当我调试它时,它说:
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] == '[=11=]' && word2[i] == '[=11=]') 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()
的 return 值: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
用于此的变量。 - 您应该使用字符文字而不是硬编码的 ASCII 值。
- 测试
if (c >= 'A' && c <= 'Z')
适用于 ASCII,它在今天几乎是通用的,但使用isupper(c)
更可靠。 - 不需要清除
buffer
,在插入单词前设置一个'[=35=]'
即可。 - 您还应该检查缓冲区溢出并拒绝处理超过 255 个字符的单词。
- 当
fp
为NULL
时,您不应调用fclose(fp)
,这是未定义的行为。
这是更正后的版本:
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] = '[=14=]'; puts(buffer); myTree = insert(myTree, buffer); i = 0; } } } fclose(fp); show(myTree); return 0; }
- 您没有检查是否向程序提供了