使用fgets()触发AddressSanitiser: SEGV on unknown address问题求助
分析fgets()触发SEGV on unknown address的原因及修复方案
嘿,我太懂这种从scanf转fgets突然炸段错误的憋屈了!咱们来一步步拆解问题,找到根因和修复办法:
最可能触发SEGV的几个坑
1. 给fgets传了野指针/未初始化指针
这是90%概率会碰到的问题!举个反例:
char *buf; // 这里buf是未初始化的野指针,指向随机内存 fgets(buf, 100, stdin); // 往随机内存写,直接触发段错误
之前用scanf的时候如果也是用这个野指针,其实已经是未定义行为了——只是运气好没触发崩溃而已。而fgets一写就炸,只是刚好撞上了非法内存区域。
正确的做法是用已分配的可写内存:
- 要么用栈上的固定数组(简单安全,推荐):
char buf[256]; - 要么用堆分配的指针(适合动态大小):
char *buf = malloc(256);(记得用完free)
2. 传递了只读内存的指针给fgets
比如你用字符串字面量当缓冲区:
char *buf = "hello world"; // 字符串字面量存在只读数据段 fgets(buf, 20, stdin); // 尝试写入只读内存,直接炸SEGV
这种情况scanf往这里写也会炸,只是你之前的scanf用法没碰这块内存而已。
3. 缓冲区大小参数异常(少见)
如果给fgets传的大小是0或者负数,虽然C标准规定fgets会返回NULL,但某些平台下可能触发段错误——不过这种情况比前两种少见多了。
针对你的场景的修复代码
结合你说的“之前scanf正常,换fgets就炸”,大概率是指针/缓冲区的问题,给你一个安全的示例框架:
#include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { int x = -1; // 用栈上的固定大小数组当缓冲区(按需调整大小,留足空间存换行符) char input_buf[256]; // !重要:处理之前scanf留下的换行符 // 如果你之前用了scanf("%d", &x); 输入完数字按回车,换行符会留在输入缓冲区 // 这时候fgets会先读这个换行符,导致你以为输入没生效(虽然不会炸,但逻辑不对) int c; while ((c = getchar()) != '\n' && c != EOF); // 安全调用fgets:检查返回值,确保读取成功 if (fgets(input_buf, sizeof(input_buf), stdin) != NULL) { // 可选:去掉fgets读取的换行符(如果不需要保留) input_buf[strcspn(input_buf, "\n")] = '\0'; // 接下来处理输入内容 printf("你输入的内容:%s\n", input_buf); } else { fprintf(stderr, "读取输入失败\n"); return 1; } // 如果你需要动态大小的缓冲区,用堆分配: // char *dyn_buf = malloc(256); // if (dyn_buf == NULL) { // fprintf(stderr, "内存分配失败\n"); // return 1; // } // fgets(dyn_buf, 256, stdin); // // 处理内容... // free(dyn_buf); // 务必释放内存 return 0; }
额外提醒
- 永远确保fgets的第一个参数是可写的、已分配的有效内存,大小参数要和缓冲区实际大小一致(用
sizeof数组是最安全的,堆分配的话要自己跟踪大小)。 - 从scanf转fgets时,一定要清空之前scanf留下的换行符——这虽然不会导致SEGV,但会让程序逻辑不符合预期,很多人会误以为是fgets的问题。
内容的提问来源于stack exchange,提问作者FatimahFatCakes
相关产品推荐
相关产品推荐

