C 为什么这会给我一个系统的分段错误,而不是另一个?

C 为什么这会给我一个系统的分段错误,而不是另一个?,c,dictionary,pointers,segmentation-fault,trie,C,Dictionary,Pointers,Segmentation Fault,Trie,我正在运行一个程序,通过读取“words.txt”中的单词来创建字典树,然后可以进行搜索,查看树中是否有特定的单词。在上运行这个程序效果很好,但是当我尝试在自己的Linux系统上运行它时,我遇到了一个分段错误。你知道为什么吗?代码如下: #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> /* Node structure of trie */

我正在运行一个程序,通过读取“words.txt”中的单词来创建字典树,然后可以进行搜索,查看树中是否有特定的单词。在上运行这个程序效果很好,但是当我尝试在自己的Linux系统上运行它时,我遇到了一个分段错误。你知道为什么吗?代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

/* Node structure of trie */
struct node
{
    struct node *next[27]; // 26 for a-z and last one(26th index) is for apostrophe
    int end; // value as 1 denotes the end of the word.
};

/* This method is for creating a new node */
struct node *createNode()
{
    struct node *newNode = (struct node *)malloc(sizeof(struct node));
    newNode->end = 0; // set end as false i.e. 0
    for (int i = 0; i < 27; i++) // set all children as NULL
        newNode->next[i] = NULL;
    return newNode;
}

/* This method is for inserting a word in the trie */
void insert(struct node *root, char *word)
{
    struct node *curr = root;
    for (int i = 0; i < strlen(word); i++) // iterating character by character
    {
        int index;
        if (word[i] == '\'') // if character is apostrophe index is 26
            index = 26;
        else
            index = tolower(word[i]) - 'a'; // else the index as the alphabet sequence number starting from 0.
// for a - 0, b - 1, ..... z - 25
        if (!curr->next[index])
            curr->next[index] = createNode(); // create node of that character if not created yet
        curr = curr->next[index]; // then go for next character
    }
    curr->end = 1; // mark end as 1 to denote the ending of the word
}

/* This method is for searching a word in the trie */
int search(struct node *root, char *word)
{
    struct node *curr = root;
    for (int i = 0; i < strlen(word); i++) // iterating character by character
    {
/* Getting index same as insert function */
        int index;
        if (word[i] == '\'')
            index = 26;
        else
            index = tolower(word[i]) - 'a';
        if (!curr->next[index]) // if node of current character not found means the word doesn't exist in trie.
            return 0;
        curr = curr->next[index];
    }
    if (curr != NULL && curr->end) // if iterated all the characters and end is 1 then the word exists.
        return 1;
    else
        return 0; // otherwise doesn't exist.
}

int main()
{
/* Reading the file line by line */
    FILE *file;
    size_t len = 1000;
    char *word = (char *)malloc(len);
    file = fopen("word.txt", "r");
    struct node *root = createNode();
    while (fgets(word, len, file) != NULL) // iterating line by line
    {
        int len = strlen(word);
        if (word[len - 1] == '\n') // removing the newline which is at the end of the every line
            word[len - 1] = '\0';
        insert(root, word); // inserting every word
    }
    int ans;
    word = (char *)("error's"); // checking the existence of the word "error's"
    ans = search(root, word);
    if (ans == 1)
        printf("\"%s\" found!\n", word);
    else
        printf("\"%s\" not found!\n", word);
    word = (char *)("hilli");// checking the existence of the word "hilli"
    ans = search(root, word);
    if (ans == 1)
        printf("\"%s\" found!\n", word);
    else
        printf("\"%s\" not found!\n", word);
    return 0;
}
#包括
#包括
#包括
#包括
/*trie的节点结构*/
结构节点
{
结构节点*next[27];//26表示a-z,最后一个(26索引)表示撇号
int end;//值为1表示单词的结尾。
};
/*此方法用于创建新节点*/
结构节点*createNode()
{
结构节点*新节点=(结构节点*)malloc(sizeof(结构节点));
newNode->end=0;//将end设置为false,即0
for(int i=0;i<27;i++)//将所有子项设置为NULL
newNode->next[i]=NULL;
返回newNode;
}
/*此方法用于在trie中插入单词*/
空插入(结构节点*根,字符*字)
{
结构节点*curr=root;
for(int i=0;inext[索引])
curr->next[index]=createNode();//如果尚未创建,则创建该角色的节点
curr=curr->next[index];//然后选择下一个字符
}
curr->end=1;//将end标记为1表示单词的结尾
}
/*此方法用于在trie中搜索单词*/
int搜索(结构节点*根,字符*字)
{
结构节点*curr=root;
for(int i=0;inext[index])//如果未找到当前字符的节点,则表示该单词在trie中不存在。
返回0;
当前=当前->下一步[索引];
}
如果(curr!=NULL&&curr->end)//如果迭代所有字符,且end为1,则该单词存在。
返回1;
其他的
返回0;//否则不存在。
}
int main()
{
/*逐行读取文件*/
文件*文件;
尺寸长度=1000;
char*word=(char*)malloc(len);
file=fopen(“word.txt”、“r”);
结构节点*root=createNode();
while(fgets(word,len,file)!=NULL)//逐行迭代
{
int len=strlen(字);
if(word[len-1]='\n')//删除每行末尾的换行符
字[len-1]='\0';
插入(词根,单词);//插入每个单词
}
INTANS;
word=(char*)(“error’);//检查单词“error’s”是否存在
ans=搜索(根、字);
如果(ans==1)
printf(“\%s\”找到!\n”,word);
其他的
printf(“\%s\”未找到!\n”,word);
word=(char*)(“hilli”);//检查单词“hilli”的存在性
ans=搜索(根、字);
如果(ans==1)
printf(“\%s\”找到!\n”,word);
其他的
printf(“\%s\”未找到!\n”,word);
返回0;
}

以下是应该有效的代码。它确实可以在macOS 10.15.2 Catalina上工作,使用GCC 9.2.0和XCode 11.3.1,并启用编译器集Fusy和许多内存调试选项。它不会试图释放它构建的trie;它应该(能够释放您构建的结构是一个很好的练习)

它使用DOS(CRLF)和Unix(NL或LF)行结尾进行了测试,并且使用这两种行结尾都是安全的,因为它使用
strcspn()

word[strcspn(word, "\r\n")] = '\0';
如果您有旧的Mac样式的行结束符(仅限CR),那么
fgets()
无法识别行结束符会有问题,但是如果您修复了这一问题(例如使用POSIX),它也可以正确地处理这类行

对代码所做的更改基本上是装饰性的,但允许使用相当严格的选项干净地编译代码(source
trie79.c
;program
trie79
):

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
>     trie79.c -o trie79 
$

这是CS50课程的吗?使用一个包含27个元素的trie(26个字母加上一个表示其他任何内容),因此即使您没有使用
标题,它似乎也是合理的。您可能有未定义的行为。不能保证会导致错误。您有内存泄漏。你永远不会免费(word)
。在使用
word=(char*)(“错误”)重新分配之前,需要这样做
@JonathanLeffler没错,我的评论应该是“如果单词[i]不是A-Z,那么tolower(单词[i])通过为
下一个[index]形成超出范围的索引来引导UB
。代码中的哪一行导致了分段错误?您可能需要使用调试器来找出。在任何情况下,哪一行应该是您的第一个调用端口。我编译了代码,但修改很少(
static
before函数,而不是
main()
int main(void)
,并将循环从
for(int i=0;i
更改为
int length=strlen(word);for(int i=0;i
——主要是因为我的默认编译选项需要这些更改或大致相当的更改)。它适用于各种基本单词列表-在macOS 10.15.2 Catalina上。绝对完美。非常感谢!
word[strcspn(word, "\r\n")] = '\0';
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
>     trie79.c -o trie79 
$