K&R练习程序增减printf语句出现段错误/断言失败求助
问题分析与解决
嘿,这个问题的根源其实很典型——未初始化的局部变量!我来给你拆解清楚:
为什么会出现随机崩溃/断言失败?
你的itob函数里,变量i被声明了但没有初始化:
void itob(int n, char s[], unsigned b) { assert(b <= 64); int c, i, sign; // 这里i没有赋值,初始值是栈上的垃圾数据 if ((sign = n) < 0) n = -n; do { s[i++] = numtochar(n % b); // 用随机的i开始写数组,直接越界! } while ((n /= b) != 0); // ... 后续代码 }
局部变量存在栈内存中,声明后如果不初始化,会保留栈里之前的残留值(垃圾数据)。当你保留printf时,printf的调用会修改栈内存的状态,刚好让i的初始值变成了0,程序侥幸正常运行;但去掉printf后,i的初始值是随机的垃圾数,直接往数组s的随机位置写数据,大概率会越界覆盖其他内存(比如栈上的断言变量、函数返回地址),导致段错误或者断言失败。
修复步骤
1. 初始化i为0
把itob里的变量声明改成:
int c, i = 0, sign;
这样就从数组s的第一个位置(s[0])开始写入数据,不会越界了。
2. 额外优化:处理INT_MIN的溢出问题
当前代码里n = -n;存在隐患:当n是INT_MIN(比如32位系统的-2147483648)时,-n会超出int的正数范围(int最大是2147483647),导致整数溢出,这是未定义行为。可以改成用unsigned int来处理负数:
void itob(int n, char s[], unsigned b) { assert(b <= 64); int i = 0; unsigned int un = n; int is_negative = n < 0; if (is_negative) { un = -un; // unsigned类型的负数转换是合法的,会自动转成补码对应的正数 } do { s[i++] = numtochar(un % b); } while ((un /= b) != 0); if (is_negative) { s[i++] = '-'; } s[i] = '\0'; reverse(s); return; }
验证修复效果
修改后,不管你注释掉多少printf语句,程序都能稳定运行,所有断言都会通过,不会再出现段错误或者断言失败的问题。
内容的提问来源于stack exchange,提问作者user8505916
相关产品推荐
相关产品推荐

