空for循环意外修复C语言单项式读取函数Bug的原因咨询
C语言单项式解析函数异常问题
问题背景
我正在为即将到来的测试准备编程练习,偶然修复了一个代码问题但始终不清楚底层原理,特此求助。
本次练习要求:
- 定义可表示含x、y、w、z四个变量的单项式的结构体类型
- 实现
print_term函数,用于在屏幕输出单项式 - 实现
read_term函数,用于读取用户输入并返回对应单项式
用户输入需遵循固定格式:C V P V P V P V P .,其中C为单项式系数,V为4个变量之一(输入顺序不限),P为对应变量的幂次。
给定的单项式结构体定义如下:
// 单项式结构体定义 struct term{ int coef; // 系数 int potx; // x的幂次 int poty; // y的幂次 int potw; // w的幂次 int potz; // z的幂次 };
故障现象
read_term函数存在逻辑异常:当输入的系数C为负数时,某一变量的幂次会被错误赋值为-48,该值明显来自数字字符转整型数值的计算逻辑。
- 负系数测试用例:输入
-257 x 2 z 3 w 1 .,错误返回结果为-257(x^2)(w^-48)(z^3) - 正系数测试用例:输入
257 x 2 z 3 w 1 .,可正确返回结果257(x^2)w(z^3)
问题代码如下:
struct term read_term(){ struct term result; result.coef =0; result.potx =0; result.poty =0; result.potw =0; result.potz =0; char input[255]; for(int i =0; i < sizeof(input)/sizeof(input[0]);i++){ input[i] = '\0'; } char inputNeg[255]; int negativo = 0; printf("Termine: \n"); fgets(input, 255, stdin); input[strlen(input)-1] = '\0'; // 移除输入末尾的换行符 // 先移除负号,后续计算完系数再补回 if(input[0] == '-'){ negativo = 1; int i = 1; do{ inputNeg[i-1] = input[i]; i++; }while(input[i] != '\0'); printf("\n%s\n", input); strcpy(input, inputNeg); printf("\n%s\n", input); } //////////// 这段空循环直接决定代码是否能正常运行 //printf("\ninput prova\n"); for(int i =0; i < sizeof(input)/sizeof(input[0]);i++){ //printf("%c", input[i]); } //////////////////////////// // 根据输入解析填充结构体字段 int index = 0; int cifreCof[12]; for(int j=0; j< sizeof(cifreCof)/sizeof(cifreCof[0]);j++){ cifreCof[j] = 0; } int temp = 0; int pot = 0; do{ // 系数固定从输入起始位置开始解析 if(index == 0){ // 字符转数字 do{ cifreCof[index] = input[index] - '0'; index++; pot++; }while(input[index] != ' '); // 拼接所有数字位为完整整数 for(int i=0; i < sizeof(cifreCof)/sizeof(cifreCof[0]); i++){ temp = temp + (cifreCof[i]*pow(10, pot-1)); pot--; } // 补回负号 if(negativo == 0){ result.coef = temp; } else{ result.coef = (-1)*temp; } } // 解析变量和对应幂次 else{ // 跳过空格 if(input[index] == ' '){ index++; } // 解析x else if(input[index] == 'x'){ index++; index++; // 目前仅支持单位数幂次 if(input[index] != '.'){ result.potx = input[index] - '0'; index++; } else{index++;} } // 解析y else if(input[index] == 'y'){ index++; index++; if(input[index] != '.'){ result.poty = input[index] - '0'; index++; } else{index++;} } // 解析w else if(input[index] == 'w'){ index++; index++; if(input[index] != '.'){ result.potw = input[index] - '0'; index++; } else{index++;} } // 解析z else if(input[index] == 'z'){ index++; index++; if(input[index] != '.'){ result.potz = input[index] - '0'; index++; } else{index++;} } else{index++;} } }while(input[index] != '\0'); return result; }
调试异常现象
排查问题时,我添加了一段遍历输入存储数组的for循环用于打印调试,意外发现该循环会让函数输出正确结果;后续删除循环内所有打印语句,仅保留空的for循环结构,程序依然能输出正确结果。
根因解释
空循环“修复”代码是典型的未定义行为触发的偶然正常现象,核心bug有两处:
- 未初始化局部数组+缺失字符串结束符
声明char inputNeg[255];时没有初始化数组,数组内存是栈上留存的随机垃圾值。处理负系数时,do-while循环仅拷贝了负号后的有效数字,没有在拷贝结束位置手动添加字符串结束符'\0'。后续调用strcpy(input, inputNeg)时,strcpy会从inputNeg起始地址一直向后读取,直到遇到随机出现的'\0'才停止拷贝,这会导致input数组的内容长度不可控,甚至可能写入越界数据。
出现-48错误的原因是:无空循环时栈内存布局刚好让input中w字符后的位置被填充为'\0'(ASCII码值为0),计算幂次时执行input[index] - '0',减去'0'的ASCII码值48,刚好得到-48,和故障现象完全吻合。 - 空循环改变了栈内存布局
空循环虽然逻辑上没有执行任何有效操作,但循环会在栈上额外申请循环变量i的内存,直接改变了栈上的内存排布,刚好覆盖了inputNeg数组后续的垃圾内存,让strcpy执行时能在预期位置读到'\0',最终输出结果正常。这种修复完全不可靠,更换编译选项、调整代码顺序、更换编译器版本都会导致bug复现。
正确修复方向
- 局部数组声明后必须初始化,处理字符串拷贝时必须手动补
'\0'结束符,处理负系数时可以直接用指针偏移读取原input数组内容,无需额外拷贝数组 - 整数幂计算不要用浮点函数
pow,避免精度误差,直接通过循环乘10拼接数字即可 - 调用
fgets移除末尾换行符时,需要先判断最后一个字符是否是'\n',避免输入为空时出现越界访问
内容的提问来源于stack exchange,提问作者Prio216
相关产品推荐
相关产品推荐

