C语言动态输入函数触发corrupted size vs. prev_size错误排查
错误根因
corrupted size vs. prev_size是glibc堆校验抛出的错误,本质是堆块的头部元数据被越界写破坏,你的代码有两个必触发的逻辑bug:
- C语言函数参数是值传递,
dynInput的形参text是main中指针的拷贝,函数内部执行realloc后得到的新内存地址,只会修改这个局部拷贝,main里的text永远指向最开始malloc返回的旧地址。一旦realloc因为原块后续空间不足、把内存移到新位置,旧地址就成了野指针,后续读写全是非法内存访问。 - 内存读写和扩容顺序完全写反了:你每次都是先往
text[i]写字符,再扩容到l字节大小。初始l=1,第一次循环写完text[0]再扩到1字节还能凑活;第二次循环i=1时,你还没扩容就写text[1],此时内存块实际只有1字节大小,直接越界写覆盖了堆块保存元数据的区域,输入超过十几个字符后,堆结构破坏累积到触发校验阈值,就会抛出你看到的错误。 - 额外隐患:
getchar()返回值是int类型,专门用来和EOF做区分,你直接存到char里,遇到输入终止(Ctrl+D/Ctrl+Z)时会进入死循环。
修复方法
- 把
dynInput的参数改成二级指针char**,传入main中text指针的地址,保证函数内部能修改外层的指针值,拿到realloc返回的新地址 - 调整操作顺序:先确认剩余空间足够,再写入字符,同时预留字符串结束符
\0的位置 - 增加
EOF判断,避免异常死循环 - 把逐字节扩容改成倍数扩容,减少
realloc调用次数,提升性能
修复后可直接运行的代码:
#include <stdio.h> #include <stdlib.h> void dynInput(char **text); int main() { char *text = malloc(sizeof(char)); if (text == NULL) return 1; while(1) { dynInput(&text); if (text[0] == '\0' && feof(stdin)) break; printf("%s\n", text); } free(text); return 0; } void dynInput(char **text) { int c; int str_len = 0; int cap = 1; // 初始容量和main中分配的1字节对应 while ((c = getchar()) != '\n' && c != EOF) { // 需要存当前新字符+末尾的'\0',容量不够就先扩容 if (str_len + 2 > cap) { cap *= 2; char *tmp = realloc(*text, cap); if (tmp == NULL) { free(*text); exit(EXIT_FAILURE); } *text = tmp; } (*text)[str_len++] = (char)c; } (*text)[str_len] = '\0'; }
补充说明
- 原代码每次只扩1字节的写法效率极低,每次写入都要触发内存分配,2倍扩容是动态数组的常规实现,性能表现好很多
- 所有内存分配操作都加了空指针判断,避免分配失败时的空指针引用
- 程序退出前主动释放申请的内存,避免运行时内存泄漏
内容的提问来源于stack exchange,提问作者lucoski
相关产品推荐
相关产品推荐

