C语言代码在在线编译器/CLion表现不稳定,VS运行异常求排查
食品库存变动统计代码的跨编译器异常问题
问题现象
这段统计食品增减变动的代码在在线C编译器上运行完全正常,但在本地IDE中出现异常:
- CLion:首次运行输出正确,第二次、第三次输出错误值,后续又恢复正常
- Visual Studio:运行完全异常
已在多台设备和在线编译器验证过代码。
原代码如下:
typedef enum { kus=1,kg } Jednotka; typedef union { int kus; float kg; } Mnozstvi; typedef enum { rohlik,chleb,brambory,sirup,merunky,cukr,cokolada,salam,mleko,kava,pivo,mouka,maso,sul,kmin,fazole,meloun } Potravina; typedef struct { Potravina potr; Jednotka jedn; Mnozstvi mnoz; } Pohyb; const Pohyb pohyb[]={{chleb,kg,{.kg=20}},{cukr,kg,{.kg=10}},{rohlik,kus,{.kus=70}},{cokolada,kus,{.kus=15}},{kava,kg,{.kg=2}},{mouka,kg,{.kg=5}}, {salam,kg,{.kg=6.5}},{mleko,kus,{.kus=30}},{brambory,kg,{.kg=40}},{merunky,kg,{.kg=8}},{sirup,kus,{.kus=18}},{mouka,kg,{.kg=5}}, {cukr,kg,{.kg=-1.5}},{cokolada,kus,{.kus=-2}},{brambory,kg,{.kg=-5}},{rohlik,kus,{.kus=-10}},{pivo,kus,{.kus=10}}, {kmin,kg,{.kg=.06}},{fazole,kg,{.kg=5}},{chleb,kg,{.kg=-1}},{mleko,kus,{.kus=-2}},{sirup,kus,{.kus=-1}},{pivo,kus,{.kus=25}}, {kava,kg,{.kg=6.5}},{mouka,kg,{.kg=-4}},{fazole,kg,{.kg=-.5}},{cukr,kg,{.kg=-2}},{cokolada,kus,{.kus=-3}},{sul,kg,{.kg=6}}, {brambory,kg,{.kg=-3.5}},{merunky,kg,{.kg=-.5}},{sirup,kus,{.kus=-3}},{mouka,kg,{.kg=5}},{pivo,kus,{.kus=-1}}, {mouka,kg,{.kg=-2}},{maso,kg,{.kg=10}},{maso,kg,{.kg=5.5}},{rohlik,kus,{.kus=-4}},{chleb,kg,{.kg=-3}},{rohlik,kus,{.kus=-35}}, {sirup,kus,{.kus=5}},{cokolada,kus,{.kus=-2}},{salam,kg,{.kg=-.3}},{merunky,kg,{.kg=-3}},{maso,kg,{.kg=-.5}},{maso,kg,{.kg=-.8}}, {meloun,kg,{.kg=22.5}},{meloun,kg,{.kg=-3.2}},{chleb,kg,{.kg=-.5}},{sirup,kus,{.kus=-1}},{mleko,kus,{.kus=-4}},{sul,kg,{.kg=-1}}, {rohlik,kus,{.kus=20}},{maso,kg,{.kg=-1.5}},{pivo,kus,{.kus=-8}}}; const unsigned POHYB=sizeof pohyb/sizeof *pohyb; const char *nazev[]={"rohlik","chleb","brambory","sirup","merunky","cukr","cokolada","salam","mleko","kava","pivo","mouka","maso","sul","kmin","fazole","meloun"}; #include <stdio.h> int main() { int pocetPotravin = sizeof nazev / sizeof nazev[0]; // 17 typedef struct { Potravina nazev; float myMnz; Jednotka myJedn; } vysPohyb; vysPohyb vyspohyb[pocetPotravin]; for (int i = 0; i < pocetPotravin; ++i) { vyspohyb[i].nazev = i; } for (int i = 0; i < POHYB; ++i) { if (pohyb[i].jedn == 2) { vyspohyb[pohyb[i].potr].myMnz = vyspohyb[pohyb[i].potr].myMnz + pohyb[i].mnoz.kg; vyspohyb[pohyb[i].potr].myJedn = pohyb[i].jedn; } else { vyspohyb[pohyb[i].potr].myMnz = vyspohyb[pohyb[i].potr].myMnz + pohyb[i].mnoz.kus; vyspohyb[pohyb[i].potr].myJedn = pohyb[i].jedn; } } for (int i = 0; i < pocetPotravin; ++i) { if (vyspohyb[i].myJedn == 2) { printf("%s %g kg \n", nazev[vyspohyb[i].nazev], vyspohyb[i].myMnz); } else { printf("%s %g ks \n", nazev[vyspohyb[i].nazev], vyspohyb[i].myMnz); } } }
问题根源
核心问题是未初始化局部结构体数组vyspohyb的myMnz和myJedn成员:
- 局部变量默认存储在栈内存中,栈内存的初始值是随机的垃圾数据
- 在线编译器每次运行都会重置栈环境,垃圾值恰好不影响计算结果;而本地IDE(如VS、CLion)的栈复用机制会导致多次运行时垃圾值不一致,出现时好时坏的异常
- 代码中仅初始化了
nazev成员,myMnz(用于累加库存变动)和myJedn(存储单位)的初始值都是随机值,累加计算时会把垃圾值也包含进去,导致结果错误
修复方案
初始化vyspohyb数组的所有成员,将myMnz设为0(库存初始值为0),myJedn初始化为0(后续会被实际操作覆盖)。修复后的代码如下:
typedef enum { kus=1,kg } Jednotka; typedef union { int kus; float kg; } Mnozstvi; typedef enum { rohlik,chleb,brambory,sirup,merunky,cukr,cokolada,salam,mleko,kava,pivo,mouka,maso,sul,kmin,fazole,meloun } Potravina; typedef struct { Potravina potr; Jednotka jedn; Mnozstvi mnoz; } Pohyb; const Pohyb pohyb[]={{chleb,kg,{.kg=20}},{cukr,kg,{.kg=10}},{rohlik,kus,{.kus=70}},{cokolada,kus,{.kus=15}},{kava,kg,{.kg=2}},{mouka,kg,{.kg=5}}, {salam,kg,{.kg=6.5}},{mleko,kus,{.kus=30}},{brambory,kg,{.kg=40}},{merunky,kg,{.kg=8}},{sirup,kus,{.kus=18}},{mouka,kg,{.kg=5}}, {cukr,kg,{.kg=-1.5}},{cokolada,kus,{.kus=-2}},{brambory,kg,{.kg=-5}},{rohlik,kus,{.kus=-10}},{pivo,kus,{.kus=10}}, {kmin,kg,{.kg=.06}},{fazole,kg,{.kg=5}},{chleb,kg,{.kg=-1}},{mleko,kus,{.kus=-2}},{sirup,kus,{.kus=-1}},{pivo,kus,{.kus=25}}, {kava,kg,{.kg=6.5}},{mouka,kg,{.kg=-4}},{fazole,kg,{.kg=-.5}},{cukr,kg,{.kg=-2}},{cokolada,kus,{.kus=-3}},{sul,kg,{.kg=6}}, {brambory,kg,{.kg=-3.5}},{merunky,kg,{.kg=-.5}},{sirup,kus,{.kus=-3}},{mouka,kg,{.kg=5}},{pivo,kus,{.kus=-1}}, {mouka,kg,{.kg=-2}},{maso,kg,{.kg=10}},{maso,kg,{.kg=5.5}},{rohlik,kus,{.kus=-4}},{chleb,kg,{.kg=-3}},{rohlik,kus,{.kus=-35}}, {sirup,kus,{.kus=5}},{cokolada,kus,{.kus=-2}},{salam,kg,{.kg=-.3}},{merunky,kg,{.kg=-3}},{maso,kg,{.kg=-.5}},{maso,kg,{.kg=-.8}}, {meloun,kg,{.kg=22.5}},{meloun,kg,{.kg=-3.2}},{chleb,kg,{.kg=-.5}},{sirup,kus,{.kus=-1}},{mleko,kus,{.kus=-4}},{sul,kg,{.kg=-1}}, {rohlik,kus,{.kus=20}},{maso,kg,{.kg=-1.5}},{pivo,kus,{.kus=-8}}}; const unsigned POHYB=sizeof pohyb/sizeof *pohyb; const char *nazev[]={"rohlik","chleb","brambory","sirup","merunky","cukr","cokolada","salam","mleko","kava","pivo","mouka","maso","sul","kmin","fazole","meloun"}; #include <stdio.h> int main() { int pocetPotravin = sizeof nazev / sizeof nazev[0]; // 17 typedef struct { Potravina nazev; float myMnz; Jednotka myJedn; } vysPohyb; vysPohyb vyspohyb[pocetPotravin]; // 初始化所有成员:库存初始值设为0,单位初始化为0 for (int i = 0; i < pocetPotravin; ++i) { vyspohyb[i].nazev = i; vyspohyb[i].myMnz = 0.0f; vyspohyb[i].myJedn = 0; } for (int i = 0; i < POHYB; ++i) { if (pohyb[i].jedn == kg) { // 用枚举常量替代魔法数字2,提升可读性 vyspohyb[pohyb[i].potr].myMnz += pohyb[i].mnoz.kg; vyspohyb[pohyb[i].potr].myJedn = pohyb[i].jedn; } else { vyspohyb[pohyb[i].potr].myMnz += pohyb[i].mnoz.kus; vyspohyb[pohyb[i].potr].myJedn = pohyb[i].jedn; } } for (int i = 0; i < pocetPotravin; ++i) { if (vyspohyb[i].myJedn == kg) { printf("%s %g kg \n", nazev[vyspohyb[i].nazev], vyspohyb[i].myMnz); } else { printf("%s %g ks \n", nazev[vyspohyb[i].nazev], vyspohyb[i].myMnz); } } return 0; }
额外优化说明
- 将判断条件中的魔法数字
2替换为枚举常量kg,避免硬编码,提升代码可读性和维护性 - 使用
+=运算符替代= a + b的写法,简化代码逻辑 - 增加
return 0;语句,符合C标准中main函数的返回规范
内容的提问来源于stack exchange,提问作者dejvoos
相关产品推荐
相关产品推荐

