有人可以帮我找到段错误吗?

时间:2016-03-30 13:35:56

标签: c pointers segmentation-fault trie

编辑:所以,事实证明'索引'当时没有被归还给0。这修复了一个段错误。但仍然得到一个不同的段错误。正在努力。

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

(...)

4 个答案:

答案 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++;
        }
    }