全局指针在函数/递归中无法访问结构体致程序核心转储求助
C语言字典实现核心转储与节点指针Nil问题修复
问题复盘
实现字典功能时出现以下异常:
- 全局指针调用函数能传递地址,但访问下一个节点时返回
(nil) generate函数内打印节点指针正常,但程序在第231行(any->is_word = 1处)核心转储- 测试
length=1、tmp_word="a"场景时,第214行any->character[0]输出nil - 调整全局变量逻辑后问题未解决
核心问题根源
generate函数误用全局root变量:递归创建trie节点时,每次都给全局root赋值,导致上层节点的character[i]指针被后续递归的malloc覆盖,最终上层节点的子节点指针指向错误地址,甚至变成野指针。assign函数硬编码索引:处理单词时固定访问any->character[1],不符合字母映射逻辑,导致访问错误的空节点。- 语法错误:
assign函数中any->is_word = 1末尾缺少分号,触发未定义行为,直接引发核心转储。 hash_函数内存管理错误:每次处理完单词后free(tmp_word),但后续循环未重新分配内存,导致后续使用野指针。- 递归函数未传递返回值:
check_trie、check_trie_v2、check_hash的递归调用没有返回结果,导致判断逻辑失效。
具体修复方案
修复generate函数
将全局root替换为局部变量,避免递归时覆盖上层指针:
trie *generate(int times) { trie *node = malloc(sizeof(trie)); node->next = NULL; node->is_word = false; // 初始化is_word为false if (times > 0) { for (int i = 0; i < nodes; i++) { node->character[i] = generate(times - 1); } } else { for (int i = 0; i < nodes; i++) { node->character[i] = NULL; } node->next = malloc(sizeof(hash_table)); node->next->next = NULL; } return node; }
修复assign函数
补充分号,并根据字符计算正确索引:
void assign(trie *any, int length, int index, char *tmp_word) { printf("%p\n", any); printf("%p\n", any->character[0]); if (length != 0) { int idx; if (tmp_word[index] != '\'') { idx = tolower(tmp_word[index]) - 'a'; // 统一转小写计算索引 assign(any->character[idx], length - 1, index + 1, tmp_word); } else { idx = 26; assign(any->character[idx], length - 1, index + 1, tmp_word); } } else { any->is_word = true; // 只有length==0时标记为单词节点 } return; }
修复hash_函数的内存管理
每次循环重新分配tmp_word,避免野指针:
void hash_(trie *any) { char *tmp_word; char c; for (int i = 0; dict_word[i] != '\0'; i++) { if (dict_word[i] == '\n') { continue; } tmp_word = calloc(1, 46); int j = 0; while (dict_word[i] != '\n' && dict_word[i] != '\0') { c = dict_word[i]; tmp_word[j++] = c; i++; } tmp_word[j] = '\0'; // 手动添加字符串结束符 int length = strlen(tmp_word); if (length <= heigth) { assign(root, length, 0, tmp_word); } else { assign_v2(root, heigth, 0, tmp_word); } free(tmp_word); count_words++; // 统计单词数量 } }
修复递归函数的返回值传递
bool check_trie(const char *word, int length, trie *any, int index) { if (any == NULL) return false; // 空节点直接返回false if (length != 0) { int idx; if (word[index] == '\'') { idx = 26; return check_trie(word, length - 1, any->character[idx], index + 1); } else { idx = tolower(word[index]) - 'a'; return check_trie(word, length - 1, any->character[idx], index + 1); } } return any->is_word; } bool check_trie_v2(const char *word, int length, trie *any, int index) { if (any == NULL) return false; if (length != 0) { int idx; if (word[index] == '\'') { idx = 26; return check_trie_v2(word, length - 1, any->character[idx], index + 1); } else { idx = tolower(word[index]) - 'a'; return check_trie_v2(word, length - 1, any->character[idx], index + 1); } } return check_hash(word, any->next); } bool check_hash(const char *word, hash_table *any) { if (any == NULL) return false; if (strcmp(word, any->word) == 0) { return true; } return check_hash(word, any->next); }
修复assign_v2b函数的链表插入逻辑
原代码修改形参不会影响实参,需通过指针修改:
void assign_v2b(hash_table **any, char *tmp_word) { hash_table *new_node = malloc(sizeof(hash_table)); strcpy(new_node->word, tmp_word); new_node->next = *any; *any = new_node; } // 调用时改为:assign_v2b(&any->next, tmp_word);
内容的提问来源于stack exchange,提问作者DumbDumbie
相关产品推荐
相关产品推荐

