【发布时间】:2015-09-29 20:57:33
【问题描述】:
我正在尝试实现拼写检查器,其中一个步骤是将字典加载到 trie 结构中。根据我的理解,我使用 GDB 确定每次尝试将 current->children 分配给一个值时都会遇到分段错误。底部有完整代码,但有问题的方法:
bool load(const char* dictionary)
{
FILE* dic = fopen(dictionary, "r");
if(dic == false)
{
return false;
}
root = calloc(27, sizeof(node));
node* current = NULL;
/**for(int i=0;i<27;i++)
{
current->children[i]=NULL;
}*/ //this will be the location of the segmentation fault if uncommented
int a = 0;
while((a = fgetc(dic)) != EOF)
{
if (a == '\n')
{
//this is the end of a word
if(!current->is_word)
{
//duplicate case
current->is_word = true;
wordcounter++;
}
current = root;
}
else
{
if(current->children[a-'a'] == NULL)
{
current->children[a-'a'] = calloc(27,sizeof(node));
}
current = current->children[a-'a'];
}
}
if(current!= root && !current->is_word)
{
current->is_word = true;
wordcounter++;
}
fclose(dic);
return true;
}
那里有注释代码,我在检查 stackoverflow 上的其他几个答案后尝试实现,但这只会导致在 for 循环中发生分段错误。否则发生在if(current->children[a-'a']==NULL){...}
这里发生了什么?我以为calloc()自动将分配的内存设置为0?我触摸了哪些我不应该触摸的记忆?
下面是完整的.c:
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include "dictionary.h"
typedef struct node
{
bool is_word;
struct node* children[27];
}
node;
node* root;
int wordcounter=0;
//Returns true if word is in dictionary else false.
bool check(const char* word)
{
node* current = root;
int b = 0;
while(word[b] != '\n')
{
int letter = tolower(word[b]);
if(letter == '\'')
{
return false;
}
if(current->children[letter-'a'] != NULL)
{
current = current->children[letter-'a'];
b++;
}
else
{
return false;
}
}
if(current->is_word == true)
{
return true;
}
return false;
}
// Loads dictionary into memory. Returns true if successful else false.
bool load(const char* dictionary)
{
FILE* dic = fopen(dictionary, "r");
if(dic == false)
{
return false;
}
root = calloc(27, sizeof(node));
node* current = NULL;
/**for(int i=0;i<27;i++)
{
current->children[i]=NULL;
}*/
int a = 0;
while((a = fgetc(dic)) != EOF)
{
if (a == '\n')
{
//this is the end of a word
if(!current->is_word)
{
//duplicate case
current->is_word = true;
wordcounter++;
}
current = root;
}
else
{
if(current->children[a-'a'] == NULL)
{
current->children[a-'a'] = calloc(27,sizeof(node));
}
current = current->children[a-'a'];
}
}
if(current!= root && !current->is_word)
{
current->is_word = true;
wordcounter++;
}
fclose(dic);
return true;
}
//Returns number of words in dictionary if loaded else 0 if not yet loaded.
unsigned int size(void)
{
return wordcounter;
}
//Unloads dictionary from memory. Returns true if successful else false.
void memFree(node* current)
{
for(int i = 0; i < 27; i++)
{
if(current->children[i] !=NULL)
{
memFree(current->children[i]);
}
}
free(current);
}
bool unload(void)
{
memFree(root);
return true;
}
【问题讨论】:
-
node* current = NULL; ... current->children- 当然会出现段错误。您正在取消引用一个空指针。 -
哇,我怎么会错过呢?我将其更改为简单的
node* current;,但这安全吗?我在一本小字典上运行它,它运行良好,但对于更大的字典,它就崩溃了。 -
不,这是从未初始化的变量中读取的,该变量也具有未定义的行为。你的意思是
current = root;吗? -
啊,是的。我要去泡杯咖啡,想想我在这里做了什么,呵呵。干杯,谢谢。 - 想添加以上作为答案,以便我可以解决?我会觉得忘恩负义地把答案贴出来。
标签: c io segmentation-fault trie calloc