[英]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
. 我尝试使用
Valgrind
和GDB
对其进行调试。 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()
函数不一定返回0
到26
范围内的值。 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.