node* new_node(void){
node* ptr = malloc(sizeof(node));
for (int i = 0; i<27; i++) {
ptr->next[i] = NULL;
}
return ptr;
}
bool load(const char* dictionary)
{
FILE* dict = fopen(dictionary, "r");
node* ptr = new_node;
char word[LENGTH+1];
int index = 0;
for (int c = fgetc(dict); c!=EOF; c = fgetc(dict)){
if(c!='\n'){
word[index]=c;
index++;
}
else {
for(int x=0; x<=index; x++){
int ch = (word[x] == '\'') ? 26 : tolower(word[x])-'a';
if (ptr->next[ch] == NULL){
ptr->next[ch] = new_node;
}
ptr = ptr->next[ch];
}
ptr->end=true;
}
}
return true;
}
我试图为字典实现trie数据结构,但我的程序似乎在这个函数中的某个地方发生了段错误。即使在GDB的帮助下,我似乎无法将其固定下来,那么有人可以帮我一把吗?
节点定义如下:
typedef struct node{
bool end;
struct node* next[27];
} node;
字典文件:
a
aaa
aaas
aachen
aalborg
aalesund
aardvark
aardvark's
aardvarks
aardwolf
(...)
答案 0 :(得分:4)
您的代码中存在许多问题:
使用malloc
分配内存时,它是未初始化的。在分配之后直接初始化它,以便NULL
指针确实为空。 (calloc
,是'malloc'的堂兄弟,将所有记忆初始化为零。)
当你循环翻译时,你也不应该包括index
:
for (int x = 0; x < index; x++) ...
找到单词的结尾后,必须将index
重置为0.否则,您将追加旧单词并溢出缓冲区。 (您可能还应该强制执行'index'的上限。)
同样,当您在trie中插入一个单词时,必须重置指针,以便遍历trie的根目录。你需要两个指针:一个根节点指针和一个用于遍历trie的辅助指针。
原样,您的trie是您的功能的本地。返回根节点,以便其他函数可以使用trie,或NULL
失败。
修复这些问题,你将拥有一个非崩溃的功能。 (它仍会泄漏内存,可能无法正确构建特里。)
node *load(const char *dictionary)
{
FILE *dict = fopen(dictionary, "r");
node *head = calloc(1, sizeof(node));
char word[LENGTH + 1];
int index = 0;
for (int c = fgetc(dict); c != EOF; c = fgetc(dict)) {
if (c != '\n') {
word[index] = c;
index++;
} else {
node *ptr = head;
for (int x = 0; x < index; x++) {
int ch = (word[x] == '\'') ? 26 : tolower(word[x]) - 'a';
if (ptr->next[ch] == NULL) {
ptr->next[ch] = calloc(1, sizeof(node));
}
ptr = ptr->next[ch];
}
ptr->end = true;
index = 0;
}
}
return head;
}
答案 1 :(得分:3)
您忘记在循环开始时将index
重置为0
。
您还应该使用calloc(1, sizeof(node))
代替malloc(sizeof(node))
,以避免将内存保留为未初始化状态。我建议您使用valgrind来帮助您在代码中跟踪此类问题。
答案 2 :(得分:2)
该行:
node* ptr = new_node;
和
ptr->next[ch] = new_node;
不调用该函数,而是将函数的地址分配给ptr
。请改为调用该函数。
如果编译器警告:-Wall
和-Wextra
已启用,则可能会阻止此问题。
数组word
上没有进行边界检查。在使用之前,请使用值LENGTH
检查索引是否在边界内。
不清楚for循环中的if语句是做什么的。似乎每次找到换行符时,整个数组word
都会添加到树中,但index
不会被重置,因此会多次添加相同的数组。在某些时候index
将指出超出界限导致未定义的行为。您应该在使用数组index
后重置word
。
答案 3 :(得分:2)
您应该更多地过滤标点符号\不支持的字符。由于
,[a-z|A-Z|\n|\\]
之外的任何字符都会导致程序崩溃
int ch = (word[x] == '\'') ? 26 : tolower(word[x])-'a';
if (ptr->next[ch] == NULL){
鉴于您打开文件,某处可能存在空格或某些意外字符。你需要像
这样的东西 if(c!='\n'){
int num = (c == '\'') ? 26 : tolower(c)-'a');
if(num >=0 && num < 27)
{
word[index]=c;
index++;
}
}