while 循环中“scanf 被跳过”或者“无限循环一个输入”或者“scanf 死循环”的 bug 总结

今天一天都被这个 bug 烦到头疼。我的 GetScoreData 函数中是从文本中读取一大串的输入。但是 debug 的过程中发现,只要是输入 1 以外的任何数,循环都能正常进行,每次都会停下来等我重新输入。独独只有输入 1 的情况下, 会无限循环 1 中的内容且我根本无法输入。debug 显示 choice 的值也始终为 1,于是我判定是 GetScoreData 函数中出了问题。

int main()
{
	...
	...
	while (1)
    {
        scanf("%d", &choice);
        switch(choice) // 根据用户输入进入不同的模块
        {
            case 1:
                GetScoreData();
                break;
            case 2:
                CountTotalScore();
                break;
        }
        printf("\n请输入您的选择(1-9):\n");

    }
    ...
    ...
}

我的 GetScoreData 函数的主体代码是这样的:

void GetScoreData()
{
	fropen("input.txt", "r", stdin);
	...
	...
	...
	fclose(stdin);
}

使用 fropen 函数的原因在于PAT算法笔记总结(一)第 17 点中讲到的那样,能够省去重复的复制粘贴测试数据的过程。但是在此处,由于不知名的原因,它会使得 main 函数中的 scanf 不停地得到来自其他地方的输出,从而使得 GetScoreData 函数被无限执行。也由此产生了 scanf 函数被跳过的现象。我把这两段代码删去后,程序就恢复了正常,果然还是不能偷懒,脚踏实地才是真呐…

网上也有其他的 while 中 scanf 被跳过或者只执行一次的 bug,我这个算是意外之外的 bug。这里把网上的该 bug 总结一下,我提取出所有该问题的主体代码如下:

while (1)
{
	...
	scanf("%c", &c);
	... // 后面的语句是判定字符变量 c
}

这个问题主要表现为:无限循环。其原因在于,计算机的输入首先是进入到缓冲区中的。当你输入字符 a + 回车 之后,你的 a 被读取给了 字符变量 c,回车符则留在了缓冲区中。第一个循环执行完之后,scanf 会首先进入缓冲区读取数据,发现读取到的是回车符,而判断语句中没有针对回车符的分支,于是会进入下次循环。下次循环又读取到回车符,于是又进入下下次循环,从而出现死循环的 bug。解决办法有两个,都是在 scanf 后加上一条语句:

  1. fflush(stdin)。该函数会清空缓冲区中的数据,从而在下次循环 scanf 需要用户提供输出而不是到空的缓冲区中读取数据。
  2. getchar()。用 getchar 接受回车符,也就将其过滤掉了,也能实现上述的效果。

当 scanf 是读入整数时就不需要用上述的方法,因为此时 scanf 会默认跳过缓冲区中的所有字符,当缓冲区无整数时,则会停下来等待用户的输入。


希望本篇博客能对你有所帮助,也希望看官能动动小手点个赞哟~~。

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
好的,我可以为您提供这样一个小游戏的代码示例: ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #define MAX_WORD_LEN 50 #define MAX_DEF_LEN 200 #define MAX_WORDS 1000 void read_words(char words[][MAX_WORD_LEN], char definitions[][MAX_DEF_LEN], int *num_words) { FILE *fp = fopen("bug.txt", "r"); if (fp == NULL) { printf("Failed to open file\n"); exit(1); } char line[MAX_WORD_LEN + MAX_DEF_LEN]; *num_words = 0; while (fgets(line, sizeof(line), fp) != NULL) { int i = 0; while (line[i] != ' ') { words[*num_words][i] = line[i]; i++; } words[*num_words][i] = '\0'; strcpy(definitions[*num_words], &line[i+1]); (*num_words)++; } fclose(fp); } int main() { char words[MAX_WORDS][MAX_WORD_LEN]; char definitions[MAX_WORDS][MAX_DEF_LEN]; int num_words; read_words(words, definitions, &num_words); srand(time(NULL)); int score = 0; printf("Welcome to the C word game!\n"); printf("Type 'exit' to quit the game.\n"); while (1) { int idx = rand() % num_words; printf("\n%s: ", definitions[idx]); char answer[MAX_WORD_LEN]; scanf("%s", answer); if (strcmp(answer, "exit") == 0) { printf("Final score: %d\n", score); break; } else if (strcmp(answer, words[idx]) == 0) { printf("Correct!\n"); score++; } else { printf("Incorrect. The correct answer is '%s'\n", words[idx]); } } return 0; } ``` 这个程序首先会读取 `bug.txt` 文件的单词和汉语意思,然后进入一个循环,每次随机选择一个单词的汉语意思并要求玩家输入对应的英文单词。如果输入的单词与正确的单词相同,则得分加一;否则显示正确的单词并继续下一轮游戏。玩家可以输入 `exit` 来退出游戏,此时会显示最终得分。 请注意,这个程序只是一个简单的示例,还有很多地方可以改进和完善。例如,可以添加难度等级、计时器、更友好的用户界面等功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值