C语言使用scanf()时如何忽略特定扫描调用?附数学游戏优化咨询
问题根因分析
你遇到的需额外输入数字的问题以及隐藏bug如下:
scanf("%s%i", foo, &bar)的格式串要求必须连续输入一个字符串+一个整数,缺少任意一个参数scanf都会阻塞等待用户输入,所以单独输入show-stats时程序会一直等待后续整数输入,这就是需要多输入0的原因。char foo[] = ""定义的字符数组长度仅1字节(只能存字符串结束符\0),输入任意长度大于0的字符串都会发生缓冲区溢出,属于严重内存越界bug,会破坏程序其他变量的数值。- 字符串匹配逻辑写反:
strcmp判断两个字符串相等时返回0,你原代码的if(strcmp(foo,"show-stats"))逻辑是输入不是show-stats的时候才打印分数,完全不符合预期。
最小复现代码修复方案
#include <stdio.h> #include <string.h> int main() { int bar = 0; // 给字符串预留足够缓冲区 char foo[100] = {0}; int score = 1; char input_buf[128] = {0}; // 先读整行避免输入阻塞 fgets(input_buf, sizeof(input_buf), stdin); // 尝试匹配字符串+整数,返回值是成功匹配的参数个数 int match_cnt = sscanf(input_buf, "%s %i", foo, &bar); // 字符串相等时才打印统计 if(strcmp(foo,"show-stats") == 0) { printf("Score is %i\n", score); } // 成功匹配到两个参数、且bar等于2时才执行加倍逻辑 if(match_cnt == 2 && bar == 2) { score = bar * 2; printf("Doubled Points.\n"); } return 0; }
完整游戏代码优化建议
- 随机数种子初始化错误:
srand(time(NULL))不要放在死循环内部,time(NULL)返回秒级时间戳,同一秒内多次调用srand会导致生成的随机数完全重复,应该移到循环外,程序启动时仅调用一次即可。 - 变量未初始化:
score变量没有赋初始值,首次运行时的分数是内存中的随机垃圾值,建议按需求初始化为0或1。 - 减法逻辑bug:
x和y是无符号整型,当x < y时做减法会得到无符号溢出的超大数值,存入int类型的sum会变成负数,用户根本无法答对,建议生成减法题时强制要求x >= y,如果生成的x比y小就交换两者数值。 - 输入鲁棒性差:当前
scanf("%i",&ans)如果用户输入非数字内容,会直接匹配失败,输入缓冲区的垃圾数据会一直残留,导致后续所有输入都错乱,建议先读整行再判断内容是数字答案还是show-stats这类命令。 - 代码冗余:两次打印统计数据的逻辑完全重复,可以抽成单独的打印函数,传入需要的参数即可,后续修改统计项只需要改一次。
- 拼写错误:提示语
Your correct!应为You're correct!。 - 新增命令支持:把原来直接读整数的逻辑改成先读整行,先判断行内容是不是
show-stats等命令,如果是就执行对应逻辑,否则尝试转换为整数作为答案处理。
优化后完整游戏示例代码
#include <stdio.h> #include <stdlib.h> #include <time.h> #include <unistd.h> #include <string.h> #include <ctype.h> #define VER 10 #define DIV "-----" // 抽离公共打印统计函数 void print_stats(int score, int max, int correct, int wrong, int show_answer, int answer) { printf("%sStats%s\n", DIV, DIV); if (show_answer) { printf("The correct answer was %i\n", answer); } printf("Score:%i\n" "Max possible number:%i\n" "Correct Answers:%i\n" "Wrong Answers:%i\n" "%s%s%s\n", score, max, correct, wrong, DIV, DIV, DIV); } int main() { system("clear"); // 随机数种子仅初始化一次 srand(time(NULL)); unsigned int x,y; int ans,sum; unsigned int max = 10; // 初始化分数 int score = 0; char operation; int correctAnswers = 0, wrongAnswers = 0; char input_buf[128] = {0}; char cmd[64] = {0}; printf("Math game\nVersion %i.\n", VER); for (; ;) { // 生成运算数 x = rand() % max; y = rand() % max; // 生成运算类型 operation = rand() % 2; switch (operation) { case 0: operation = '+'; sum = x + y; break; case 1: operation = '-'; // 保证减法结果为正 if (x < y) { unsigned int tmp = x; x = y; y = tmp; } sum = x - y; break; } // 输出问题 printf("What is %i %c %i? (输入show-stats可直接查看统计)\n", x, operation, y); // 读整行输入 if (!fgets(input_buf, sizeof(input_buf), stdin)) { continue; } // 去掉末尾换行符 input_buf[strcspn(input_buf, "\n")] = 0; // 先判断是不是命令 if (strcmp(input_buf, "show-stats") == 0) { print_stats(score, max, correctAnswers, wrongAnswers, 0, 0); continue; } // 尝试转换为数字答案 char *endptr; ans = strtol(input_buf, &endptr, 10); // 输入不是有效数字 if (endptr == input_buf || !isspace(*endptr) && *endptr != 0) { printf("输入无效,请输入数字答案或者show-stats命令\n"); continue; } // 判断答案正误 if (ans == sum) { score++; correctAnswers++; max++; printf("You're correct! +1!\n"); print_stats(score, max, correctAnswers, wrongAnswers, 0, 0); } else { score--; wrongAnswers++; if(max>10) { max--; } printf("Wrong! -1\n"); print_stats(score, max, correctAnswers, wrongAnswers, 1, sum); } } return 0; }
内容的提问来源于stack exchange,提问作者cs07
相关产品推荐
相关产品推荐

