C语言:无前置printf调用时触发段错误问题排查
段错误根本原因定位
你遇到的是C语言开发里非常典型的未定义行为引发的偶发崩溃,核心bug出在内存分配的尺寸计算上,和printf语句本身没有任何关系。
问题复现代码
fscanf(input, "%d %d", &numofusers, &numofmovies); //-----users list allocation for (int i = 0; i < numofusers; i++) { curruser->usercode = i + 1; //without this 7th line I get a segmentation fault at line 15 (without line 15 program termines successfully) printf("%d %d %d\n\n", numofusers, numofmovies, curruser->usercode); //through this line of code I understood that it does what I want it to do curruser->next = calloc(1, sizeof(struct user *)); // 错误就在这一行 curruser = curruser->next; } curruser = headuser; //-------- printf("!%d!\n", numofmovies);
核心错误点
- 内存分配尺寸传错:
calloc第二个参数你写的是sizeof(struct user *),这个值计算的是指向user结构体的指针的内存大小(32位系统为4字节,64位系统为8字节),远小于struct user结构体本身实际需要的内存长度。
为什么加/删printf会影响崩溃表现
这种“加个打印就不崩、删了打印就出问题”是堆内存越界的典型特征:
- 你申请的内存块不够大,后续给
curruser->usercode、curruser->next赋值的时候,本质是在写入超出申请范围的堆内存,属于非法越界写,从C语言标准来说这已经触发未定义行为,程序的运行结果没有任何保障。 - 保留循环内的printf时,printf函数运行过程中会申请临时栈空间、修改堆内存布局,刚好把你越界写入的那片内存区域覆盖成了可读写的合法空间,没有触发操作系统的内存保护机制,所以看起来运行正常。
- 删掉循环内的printf后,内存布局发生变化,你越界写入的内容刚好踩坏了堆内存元数据,甚至覆盖了
numofmovies变量所在的内存位置,等到执行最后一行printf读取numofmovies时,就触发了段错误。 - 如果连最后一行printf也删掉,程序没有再访问被踩坏的内存区域,跑完直接退出,就会出现“程序正常终止”的假象,但内存越界的问题始终存在,后续只要内存布局稍微变化就会崩溃。
修复方案
将错误的calloc调用修正,传入结构体本身的尺寸而非结构体指针的尺寸:
curruser->next = calloc(1, sizeof(struct user));
另外需要额外确认:进入for循环之前,headuser和初始的curruser指针已经完成了合法的内存分配、不是野指针,否则第一次循环给curruser->usercode赋值时同样会触发内存错误。
内容的提问来源于stack exchange,提问作者Luca
相关产品推荐
相关产品推荐

