scanf检测回车键致do-while循环重复执行,不用fgets如何修复?
解决scanf读取字符时捕获换行导致循环重复执行的问题
你的核心问题是输入缓冲区残留的换行符被scanf读取,导致玩家2的猜测循环意外执行两次。同时原代码中还有两个隐藏问题:Player1输入的单词包含fgets读取的换行符,导致掩码生成和最终的胜利判断逻辑失效,这也是你说"在%c前加空格会破坏校验逻辑"的根本原因。
以下是无需使用fgets替换scanf的解决步骤:
1. 清理Player1输入的换行符
fgets会把用户输入的回车键(\n)也存入数组,这会导致后续掩码长度错误、strcmp永远无法匹配(因为掩码里没有换行符)。在读取单词后立即去除换行符:
// 在fgets读取player1Word后添加 size_t wordLen = strlen(player1Word); if (wordLen > 0 && player1Word[wordLen - 1] == '\n') { player1Word[wordLen - 1] = '\0'; }
2. 修复掩码生成逻辑
原代码中掩码循环的strlen(player1Word)-1是为了跳过换行符,现在换行符已被清理,直接用单词实际长度生成掩码,并手动添加字符串结束符避免乱码:
// 替换原掩码生成代码 int actualWordLen = strlen(player1Word); for(int i = 0; i < actualWordLen; i++) { player1WordMask[i] = '_'; } player1WordMask[actualWordLen] = '\0'; // 添加字符串结束符
3. 清空scanf后的输入缓冲区
每次用scanf("%c", &player2Input)读取字符后,缓冲区会残留用户输入的换行符,下一次循环时scanf会直接读取这个换行符,导致循环重复执行。在读取字符后添加代码清空缓冲区:
// 在scanf读取player2Input后添加 scanf("%c",&player2Input); // 清空缓冲区中剩余的所有字符(直到换行) while ((getchar()) != '\n');
修改后的完整代码
#include <stdio.h> #include <string.h> #include <ctype.h> #define WORDLIMIT 12 #define NUMBER_OF_GUESSES 7 char player1Word[WORDLIMIT]; char player1WordMask[WORDLIMIT]; char player2Input; int player2GuessCount=7; int specialCharFlag = 0; int isWordAllowed = 0; int guessCorrectly = 0; int gameWon = 1; int main(void) { do //check if player 1 word is valid { // prompt and get the word printf("Player 1, enter a word of no more than %d letters:\n", WORDLIMIT-1); fgets(player1Word,WORDLIMIT,stdin); // 去除fgets读取的换行符 size_t wordLen = strlen(player1Word); if (wordLen > 0 && player1Word[wordLen - 1] == '\n') { player1Word[wordLen - 1] = '\0'; } // Player 1 enters a word with upper case letters, the program should change them to lower case. for(int i = 0; i<strlen(player1Word); i++) { player1Word[i] = tolower(player1Word[i]); } //special character flag specialCharFlag = 0; if (strlen(player1Word) >= WORDLIMIT) { printf("Enter a word of no more than %d letters:\n", WORDLIMIT-1); specialCharFlag = 1; } for (int i = 0; i < strlen(player1Word); i++) { // 判断是否为非法字符 if (!isalpha(player1Word[i])) { printf("Sorry, the word must contain only English letters.\n"); specialCharFlag = 1; break; } } isWordAllowed = (specialCharFlag == 0) ? 1 : 0; } while (isWordAllowed == 0); // 生成初始掩码 int actualWordLen = strlen(player1Word); for(int i = 0; i < actualWordLen; i++) { player1WordMask[i] = '_'; } player1WordMask[actualWordLen] = '\0'; do { // 提示玩家2当前猜测进度 printf("Player 2 has so far guessed: %s\n",player1WordMask); printf("Player 2, you have %d guesses remaining. Enter your next guess:\n",player2GuessCount); scanf("%c",&player2Input); // 清空输入缓冲区残留字符 while ((getchar()) != '\n'); player2Input = tolower(player2Input); guessCorrectly = 0; for (int i = 0; i < actualWordLen; i++) { if (player1Word[i] == player2Input) { player1WordMask[i] = player2Input; guessCorrectly = 1; } } if(guessCorrectly == 0) { player2GuessCount -= 1; } gameWon = strcmp(player1Word,player1WordMask); if(gameWon==0) { break; } } while(player2GuessCount!=0); if(gameWon == 0) { printf("Player 2 wins.\n"); } else { printf("Player 1 wins. The word was: %s\n", player1Word); } return 0; }
额外优化说明:
- 用
isalpha()简化非法字符判断,避免冗长的条件列表 - 修正单词长度判断逻辑:数组大小为WORDLIMIT,实际允许的单词长度是WORDLIMIT-1(需要留位置给字符串结束符)
- 补充了玩家2失败时的提示逻辑
内容的提问来源于stack exchange,提问作者user11270788
相关产品推荐
相关产品推荐

