C语言调用realloc时触发Segmentation error段错误问题排查
问题现象
以下是题目对应的个人实现代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> char ****get_document(char *text) { int para = 0, sen = 0, word = 0, alph = 0; char c, ****doc = (char ****)calloc(1, sizeof(char ***)); *doc = (char ***)calloc(1, sizeof(char **)); **doc = (char **)calloc(1, sizeof(char *)); for (int i = 0; i < strlen(text); i++) { c = text[i]; if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { (*(*(*(doc + para) + sen) + word)) = (char *)realloc((*(*(*(doc + para) + sen) + word)), sizeof(char) * (alph + 1)); if (((*(*(*(doc + para) + sen) + word))) == NULL) printf("NULLLLLLLLLLL"); // checking whether memory is given or not. (*(*(*(*(doc + para) + sen) + word) + alph)) = c; alph++; } else if (c == ' ') { *(*(*(doc + para) + sen) + word) = (char *)realloc((*(*(*(doc + para) + sen) + word)), sizeof(char) * (alph + 1)); *(*(*(*(doc + para) + sen) + word) + alph) = '\0'; alph = 0; word++; *(*(doc + para) + sen) = (char **)realloc((*(*(doc + para) + sen)), sizeof(char *) * (word + 1)); // memory for word. } } return doc; } void main() { char text[] = "Learning C is fun.", ****d; d = get_document(text); }
代码编译后可启动运行,但调试到字符串"Learning C is fun."中的字符'C'时,第19、20行触发Segmentation Fault段错误,同时控制台打印自定义的NULLLLLLLLLLL提示,无法定位错误根因。
错误根因
- 核心问题是realloc传入了野指针:处理完空格后,代码给单词列表realloc了
word+1个char长度的空间,但是新增的最后一个char位置(也就是用来存下一个新单词"C"的指针位)没有被初始化为NULL。realloc不会自动给新申请的内存做零初始化,这个位置存的是随机的内存垃圾值,属于野指针。 - 当处理字符'C'时,代码调用
realloc给新单词申请空间,传入的入参就是上述野指针。C标准规定realloc只有传入NULL、或者之前内存分配函数返回的合法指针时行为才是可预期的,传入野指针会直接返回NULL,这就是打印出NULL提示的直接原因。后续代码往NULL地址写入字符'C',直接触发段错误。 - 现有代码还存在其他逻辑遗漏:仅处理了空格作为单词分隔符,没有处理句子结束标点、段落换行符,也没有在循环结束后给最后一个单词补字符串结束符
\0,就算修复了当前的段错误,跑正式用例依然会出现内存问题。
修复要点
- 每次给单词、句子、段落列表realloc新增存储位后,立刻把新申请到的指针位置初始化为NULL,保证后续第一次给对应元素申请内存时,realloc传入的是合法的NULL(realloc接NULL等价于malloc,行为合法)。
- 补全分隔符处理逻辑,遍历完整个文本后给最后一个单词补
\0结束符。 - 四层指针的多层偏移写法可读性极差,很容易写错偏移层级,可以用临时变量存储当前正在操作的段落、句子、单词指针,降低写错概率。
内容的提问来源于stack exchange,提问作者Mohammad Arshad Ali
相关产品推荐
相关产品推荐

