为什么消息会打印两次?

3

我正在为C语言创建一个简单的井字游戏,这里有一个特定的函数让我遇到了问题。它应该让用户选择'X'或'O',大多数情况下它是可以工作的。但是,如果我输入一个错误的符号,它会打印出以下语句:"无效的符号,请重新输入:"两次。

为什么会这样,我该如何解决?

char assign(void)                                 
{
      char user;

      printf("Would you like to be X or O (Enter your choice): ");
      user=getchar();
      while(user != 'X' && user != 'x' && user != 'O' && user != 'o')
      {
             printf("Invalid symbol, please re-enter: ");  
             user=getchar();
      }
      if(user == 'O' || user == 'o')        return('O');
      else if(user == 'X' || user == 'x')   return('X');     
}

当你按回车键时,它可能会捕获"\n"字符。 - Lucas
1
可能是在while循环中使用getchar()的重复问题。今天早些时候还有一个while循环在到达字符之前重复两次printf()。很可能还有其他类似的问题。 - Jonathan Leffler
4个回答

4
问题的原因与换行字符有关。请使用以下方式之一的 scanf(),而不是使用 getchar()
scanf(" %c", &user);

运行得很好!比被接受的答案更好。谢谢。 - milt_on

3
你可以像这样修复它,例如:
char assign(void)
{
      char user;
      char throwaway_newline;

      printf("Would you like to be X or O (Enter your choice): ");
      user=getchar();
      throwaway_newline = getchar();
      while(user != 'X' && user != 'x' && user != 'O' && user != 'o')
      {
             printf("Invalid symbol, please re-enter: ");  
             user=getchar();
             throwaway_newline = getchar();
      }
      if(user == 'O' || user == 'o')        return('O');
      else if(user == 'X' || user == 'x')   return('X');     
}

1
如果在循环中添加一个break语句,且字符不正确,那么你将在函数底部跳出而没有实际返回一个值,因此可能会得到u作为错误的非返回值。这个被@C_Beginner_Learner加入的break语句是不合适的。未经检查地使用getchar()可能会导致问题;如果遇到EOF,你就会进入无限循环。而else if子句最好改为简单的else甚至可以去掉elseif (user == 'O' || user == 'o') return('O'); return('X'); - Jonathan Leffler
1
你可以通过在第一个响应处键入换行符或键入空格和 o(说)加换行符来将此代码驱动到循环中。第二次迭代将换行符读入 user,然后等待更多输入。我认为最简单的解决方案是使用 while (scanf(" %c", &user) == 1 && user != 'X' && user != 'x' && user != 'O' && user != 'o') { printf("Invalid symbol. Please re-enter O or X: "); 来读取字符,并使用循环 int c; while ((c = getchar()) != EOF && c != '\n') ; 之后读取直到包括换行符在内的所有内容(同时注意 EOF)。 - Jonathan Leffler
使用%c格式,它主要检测EOF(当scanf()返回EOF时)并适当处理。对于其他格式,例如读取整数的%d,它会检测EOF和输入中完全不匹配的情况,例如字母。如果你正在寻找一个数字,而下一个字符是一个字母,scanf()将返回0个转换项。如果你没有处理这个问题,就可能会陷入无限循环中(使用%c则不太容易)。输入(特别是)需要不断地小心处理——始终考虑EOF和错误条件。 - Jonathan Leffler
@JonathanLeffler; 好的。我认为如果遇到 EOF,scanf(" %c", &user)也会返回1,对吗? - haccks
@haccks:不...去阅读scanf()的规范。 - Jonathan Leffler
显示剩余4条评论

3
这是因为当你使用getchar时,它会返回下一个字符,但会将换行符留在输入缓冲区中。因此下一个getchar会返回该换行符。
你还应该注意,getchar实际上返回的是一个int而不是char
你可以通过再次使用getchar或像这样使用scanf来解决问题:
scanf("%c ", &user);

请注意上述格式中 c 后面的空格,它告诉 scanf 读取并忽略尾随的空格。
您也可以使用例如 fgets 读取一行,然后在该行上使用简单的 sscanf,这样就不需要额外的空格。

但更好的方法是使用 int user - Grijesh Chauhan
你的意思是使用另一个 getchar() 吗?但是谢谢,我会在 Stack Overflow 允许时尽快接受它。 - C_Intermediate_Learner
@C_Beginner_Learner 使用一个 getchar 获取你想要的字符,再使用一个 getchar 获取(并丢弃)换行符。 - Some programmer dude
@JoachimPileborg 谢谢,现在它可以工作了,除了重新输入有效符号后会打印一个奇怪的“u”符号。 - C_Intermediate_Learner
5
%c之后加空格可能不是一个好主意;scanf()会一直寻找输入,直到你输入了另一个非空白字符。使用" %c"(空格在前)读取任何空白字符,例如上一个输入行遗留下来的换行符,然后返回第一个非空白字符。 - Jonathan Leffler

1
你的输入缓冲区中有一个换行符。
当你按下一个既不是 [xX] 也不是 [oO] 的字符并在其后跟随一个换行符时,getchar 实际上会看到两个字符(换行符和无效字符)。
你可能希望使用 fgets 而不是依赖字符输入,并且每次忽略换行符都要调用 2 次 getchar()

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接