简体   繁体   English

在C中访问结构成员时出现段错误

[英]Getting seg fault when accessing struct member in C

I'm trying to implement a trie for storing words in C, but I'm getting a segmentation fault when trying to acess a struct member. 我正在尝试实现一个Trie以在C中存储单词,但是在尝试访问struct成员时遇到了段错误。

The code is below: 代码如下:

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

#define ALPHABET_SIZE 27
#define SIZE 45

//Trie data structure declaration
typedef struct _dictionary {
    bool is_word;
    char letter;
    struct _dictionary *children[ALPHABET_SIZE];
} dicto;

dicto *DICT;

//Function prototypes
void insert(char *string);
int toIndex(char s);

int main() {
    FILE *fp = fopen("small", "r");
    if (fp == NULL) {
        printf("Could not open file\n");
        return 1;
    }

    char word[46];

    while (fgets(word, sizeof(word), fp)) {
        insert(word);
        if (feof(fp)) {
            return 0;
        }
    }
    return 2;
}

//Inserts word into trie
void insert(char *string) {
    dicto *trav; //Pointer to walk through the trie
    trav = DICT;
    for (int n = 0; n = strlen(string); n++) {
        if (trav->children[toIndex(string[n])] == NULL) {
            trav->children[toIndex(string[n])] = malloc(sizeof(DICT));
            trav->letter = string[n];
            trav = trav->children[toIndex(string[n])];
        } else {
            trav->letter = string[n];
            trav = trav->children[toIndex(string[n])];
        }

        if (trav->letter == '\0') {
            trav->is_word = true;
        }
    }
    return;
}

/**
 * Output alphabetic index from given input
*/
int toIndex(char s) {
    s = toupper(s);
    int index = s - 65;
    return index;
}

I've tried debugging it with Valgrind and GDB . 我尝试使用ValgrindGDB对其进行调试。 The output from Valgrind is: Valgrind的输出为:

==1979== Memcheck, a memory error detector
==1979== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==1979== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==1979== Command: ./test_function1
==1979== 
==1979== Invalid read of size 4
==1979==    at 0x8048684: insert (in /home/test_function1)
==1979==    by 0x80485F7: main (in /home/test_function1)
==1979==  Address 0xffffff00 is not stack'd, malloc'd or (recently) free'd
==1979== 
==1979== 
==1979== Process terminating with default action of signal 11 (SIGSEGV)
==1979==  Access not within mapped region at address 0xFFFFFF00
==1979==    at 0x8048684: insert (in /home/test_function1)
==1979==    by 0x80485F7: main (in /home/test_function1)
==1979==  If you believe this happened as a result of a stack
==1979==  overflow in your program's main thread (unlikely but
==1979==  possible), you can try to increase the size of the
==1979==  main thread stack using the --main-stacksize= flag.
==1979==  The main thread stack size used in this run was 8388608.
==1979== 
==1979== HEAP SUMMARY:
==1979==     in use at exit: 344 bytes in 1 blocks
==1979==   total heap usage: 2 allocs, 1 frees, 4,440 bytes allocated
==1979== 
==1979== LEAK SUMMARY:
==1979==    definitely lost: 0 bytes in 0 blocks
==1979==    indirectly lost: 0 bytes in 0 blocks
==1979==      possibly lost: 0 bytes in 0 blocks
==1979==    still reachable: 344 bytes in 1 blocks
==1979==         suppressed: 0 bytes in 0 blocks
==1979== Reachable blocks (those to which a pointer was found) are not shown.
==1979== To see them, rerun with: --leak-check=full --show-leak-kinds=all
==1979== 
==1979== For counts of detected and suppressed errors, rerun with: -v
==1979== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)
Segmentation fault (core dumped)

And by running GDB, looks like the error comes from line 54: 通过运行GDB,错误似乎来自第54行:

if (trav->children[toIndex(string[n])] == NULL)

No idea on what might be happening. 不知道会发生什么。

This is just a quick answer regarding one of the possible issues with the code in the question. 这只是关于问题代码中可能出现的问题之一的快速解答。 I didn't read through the whole thing. 我没有读完整个内容。

After the following allocation, the memory is full of junk data: 在进行以下分配之后,内存中已充满了垃圾数据:

trav->children[toIndex(string[n])] = malloc(sizeof(dicto));

You would be better off either using calloc (which guarantees the memory to be zeroed out): 您最好使用calloc(这样可以保证将内存清零):

trav->children[toIndex(string[n])] = calloc(sizeof(dicto), 1);

Or zero out the data yourself: 或者自己将数据归零:

trav->children[toIndex(string[n])] = malloc(sizeof(dicto));
 memset(trav->children[toIndex(string[n])], 0, sizeof(dicto));

If you keep the junk data in the memory, than the following condition might be false even when it should be true: 如果将垃圾数据保留在内存中,则即使应为以下条件,以下条件也可能为假:

if(trav->children[toIndex(string[n])] == NULL)

PS PS

Also, sizeof(DICT) is the size of the pointer , NOT the structure . 同样, sizeof(DICT)指针的大小,而不是structure You might consider sizeof(*DICT) or sizeof(dicto) . 您可能会考虑sizeof(*DICT)sizeof(dicto)

There are multiple problems in your code: 您的代码中存在多个问题:

  • testing feof(fp) does not do what you think, it is actually unnecessary as fgets() will return NULL at end of file. 测试feof(fp)并没有您所想的那样,实际上没有必要,因为fgets()将在文件末尾返回NULL

  • the loop for (int n = 0; n = strlen(string); n++) never ends as n is recomputed as the length of the string at each iteration, Use this instead: for (int n = 0; n = strlen(string); n++)的循环for (int n = 0; n = strlen(string); n++)无休止,因为在每次迭代中n被重新计算为字符串的长度,请改用:

     for (int n = 0, len = strlen(string); n < len; n++) { 
  • when you allocate a new node, you must initialize the structure, otherwise you may have undefined behavior as the memory block returned by malloc() is uninitialized. 分配新节点时,必须初始化结构,否则可能会发生未定义的行为,因为malloc()返回的内存块未初始化。 Use calloc() instead. 请改用calloc()

  • the toIndex() function does not necessarily return a value in the range 0 to 26 . toIndex()函数不一定返回026范围内的值。 You should not hard-code the value of 'A' and you should test is the character is indeed a letter. 您不应该硬编码'A'的值,而应该测试字符确实是字母。

Here is a modified version: 这是修改后的版本:

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

#define ALPHABET_SIZE 27
#define SIZE 45

//Trie data structure declaration
typedef struct _dictionary {
    bool is_word;
    char letter;
    struct _dictionary *children[ALPHABET_SIZE];
} dicto;

dicto *DICT;

//Function prototypes
void insert(char *string);
int toIndex(char s);

int main(void) {
    char word[SIZE + 1];
    FILE *fp = fopen("small", "r");
    if (fp == NULL) {
        printf("Could not open file\n");
        return 1;
    }

    while (fgets(word, sizeof(word), fp)) {
        insert(word);
    }
    return 0;
}

//Inserts word into trie
void insert(char *string) {
    dicto *trav = DICT; //Pointer to walk through the trie

    for (int n = 0, len = strlen(string); n < len; n++) {
        int index = toIndex(string[n]);
        if (trav->children[index] == NULL) {
            trav->children[index] = malloc(sizeof(DICT));
        }
        trav->letter = string[n];
        trav = trav->children[index];
    }
    trav->is_word = true;
}

/**
 * Output alphabetic index from given input (assuming ASCII)
 */
int toIndex(char c) {
    if (c >= 'a' && c <= 'z')
        return c - 'a';
    if (c >= 'A' && c <= 'Z')
        return c - 'A';
    return 26;  /* not a letter */
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM