未使用数组b[3]缺失致C程序运行异常,求排查与修复
问题分析与修复
你遇到的问题是典型的栈内存越界写入导致的行为异常,而char b[3]只是碰巧充当了"缓冲区",掩盖了代码中的潜在错误。下面一步步拆解原因和解决方案:
核心问题原因
1. 变量x的类型与数值错误
x被声明为unsigned char,这是一个8位无符号类型,最大值仅为255。当你多次执行操作导致x累加超过255时,会发生数值溢出,x会绕回成一个小数值(比如250+10=260,260 mod 256=4),这会让代码错误地认为x<=100,继续执行越界的内存写入。- 初始
x=3是正确的(对应"man"的3个字符长度),但case 0中你把x设为2,这导致x始终和字符串的实际长度不一致,后续所有依赖x的操作都会出错。
2. case4-6中的增量与循环逻辑错误
- 比如
case4中,你想给"man"前面加上"spider"变成"spiderman",实际需要增加的长度是6("spider"的字符数),但你写了x+=7,这让x比实际字符串长度多1,导致循环操作越界。 - 循环移动字符的逻辑也有问题:你从
i=x开始移动,但x是字符串长度(不含'\0'),这会导致多移动一个位置,写入到数组a的边界之外。
3. 栈内存越界的影响
当代码越界写入a数组时,在有b[3]的情况下,越界的数据会写入到b的内存空间(因为栈上变量是连续分配的),不会影响其他关键变量;但移除b[3]后,越界写入直接覆盖了x或者f的内存,导致x的值被篡改,进而让后续的strcat或字符移动操作错误地覆盖了a的起始内容,出现输入1却输出"spider"的情况。
修复后的代码
下面是修正后的代码,解决了所有上述问题:
#include <stdio.h> #include <string.h> int main() { // 标准main函数返回int类型 char a[100] = "man"; // 移除了无用的b[3] printf("A man is bitten by a spider and becomes spiderman.\n" "So in this motive start making stuff.\nTo end the program " "just click X on top right of the window\n\n"); printf("When you create sth really big, you go back to only having " "a man.\n\n"); unsigned char f = 1; int x = 3; // 改用int类型,避免溢出,初始值对应"man"的长度 int i; // 循环变量改用int,避免unsigned的边界问题 while(1){ printf("You have a %s\n", a); printf("Press:\n" "\t1 for what you have to bite a spider.\n" "\t2 for what you have to bite a man.\n" "\t3 for what you have to bite spiderman.\n" "\t4 for what you have to get bitten by a spider.\n" "\t5 for what you have to get bitten by a man.\n" "\t6 for what you have to get bitten by spiderman.\n" "\t0 to go from the start\n"); scanf("%hhu", &f); switch(f){ case 0: strcpy(a, "man"); x = 3; // 修正x的值为3 break; case 1: if(x + 6 <= 99){ // 确保有足够空间(留1位给'\0') strcat(a, "spider"); x += 6; } break; case 2: if(x + 3 <= 99){ strcat(a, "man"); x += 3; } break; case 3: if(x + 9 <= 99){ strcat(a, "spiderman"); x += 9; } break; case 4: if(x + 6 <= 99){ // 插入"spider"到前面,增加6个字符 // 把原字符串后移6位,从最后一个字符开始 for(i = x - 1; i >= 0; i--){ a[i + 6] = a[i]; } // 写入"spider"到前6位 strncpy(a, "spider", 6); x += 6; } break; case 5: if(x + 3 <= 99){ // 插入"man"到前面,增加3个字符 for(i = x - 1; i >= 0; i--){ a[i + 3] = a[i]; } strncpy(a, "man", 3); x += 3; } break; case 6: if(x + 9 <= 99){ // 插入"spiderman"到前面,增加9个字符 for(i = x - 1; i >= 0; i--){ a[i + 9] = a[i]; } strncpy(a, "spiderman", 9); x += 9; } break; } // 检查是否超过数组容量(最多99个字符) if(x > 99){ strcpy(a, "man"); x = 3; } } return 0; // 标准main返回0 }
关键修复点说明
x改为int类型:避免了无符号溢出问题,能正确跟踪字符串长度。- 修正
x的初始值和case0的赋值:确保x始终等于字符串的实际字符长度(不含'\0')。 - 修正
case4-6的增量与循环:- 增量改为对应插入字符串的实际长度(6、3、9)。
- 循环从原字符串的最后一个字符(
x-1)开始后移,避免越界写入。
- 增加空间检查:所有操作前先判断是否有足够的数组空间(留1位给字符串终止符'\0'),彻底避免越界。
- 标准化
main函数:改为int main()并返回0,符合C语言标准。
现在你可以移除b[3],程序也能正常运行,输入1时会正确输出"You have a manspider"。
内容的提问来源于stack exchange,提问作者michalis vazaios
相关产品推荐
相关产品推荐

