【问题标题】:While loops duplicates printf two times before getting to getchar()? [duplicate]在到达 getchar() 之前,while 循环重复 printf 两次? [复制]
【发布时间】:2013-07-27 08:18:59
【问题描述】:

我目前正在自学 C 和 C++。在这个小小的“程序练习”中,我要求用户输入“i”或“d”以了解他们是要使用整数还是十进制(浮点)数。我有一个while循环,通过告诉他们是否输入了错误的字符来确保用户输入'i'或'd'。出于某种原因,while 循环中的提示在进入 getchar() 之前会打印两次。在这种情况下,我很难理解幕后发生的事情。任何帮助都非常感谢。我正在使用 Xcode(不知道它是否相关)。

#include <stdio.h>

int main()
{

  char action;

  printf("Please enter 'i' to work with integers or 'd' to work with decimals.\n\n"); 

  scanf("%c", &action); 

   while (action != 'i' || action != 'd')
   {
     printf("You didn't entered the right command. Please try again (i/d)\n");
     action = getchar()
   }
 }

所以我得到的输出是这样的:

You didn't entered the right command. Please try again (i/d)
You didn't entered the right command. Please try again (i/d)

【问题讨论】:

  • 应该是while(action != 'i' && action != 'd')?你的循环似乎永远不会停止。

标签: c while-loop


【解决方案1】:

发生的情况是,当您输入一个字符并按回车键时,您实际上是在输入两个字符 - 字符和回车符('\n')。循环对每个字符执行一次。这就是为什么你看到它经历了两次。

诀窍是明确过滤掉返回字符,如下所示:

#include <stdio.h>

int main()
{

  char action;

  printf("Please enter 'i' to work with integers or 'd' to work with decimals.\n\n"); 

  scanf("%c", &action); 

   while (action != 'i' || action != 'd')
   {
     if (action != '\n')
     {
       printf("You didn't entered the right command. Please try again (i/d)\n");
     }
     action = getchar();
   }
}

【讨论】:

  • 类似的 cmets 适用于其他答案。您可以通过使用" %c"%c 之前有一个空格)作为格式字符串来“更好地”修复它。这会跳过输入第一行上的任何前导空格。第二次使用scanf() 可能会更好。您还应该始终检查scanf() 是否报告成功;例如,如果有人从/dev/null 提供此代码输入,则循环将运行很长时间。同上getchar().
  • 嘿!非常感谢您抽出宝贵的时间。我肯定需要阅读更多关于它的内容。
  • 如果您认为此答案对您有所帮助,您可能希望通过单击左侧的复选标记“接受”它作为正确答案。
【解决方案2】:

正如Ziffusion 在他的answer 中正确诊断的那样,您会收到双重提示,因为您在用户输入错误后得到换行符作为单独的字符,这既不是i 也不是d

这是一个经过一些改进的重写:

#include <stdio.h>

int main(void)
{
    char action = '\0';

    printf("Please enter 'i' to work with integers or 'd' to work with decimals: "); 

    while (scanf(" %c", &action) == 1 && action != 'i' && action != 'd')
        printf("You didn't enter the right command. Please try again (i/d): ");

    printf("Action selected: %d\n", action);
}

发生了什么变化?

  1. 提示不以换行符结尾,因此用户的响应会立即出现在它之后。标准 I/O 通常同步标准输出和标准输入,以便刷新提示,尽管不以换行符结尾。如果没有出现提示,您可以在每个提示的printf() 语句后添加fflush(stdout);fflush(0);

  2. 检查scanf()的结果以处理EOF。

  3. scanf() 的格式包含一个前导空格。这将在返回的字符之前跳过空格,因此您会得到一个非空白、非换行符。

  4. 原始条件action != 'i' || action != 'd' 始终为真;你需要&amp;&amp;

  5. Nitpick:改进错误消息的语法。

请注意,在循环之后,如果用户触发了 EOF(键入 Control-D 或等效项),则操作可能不是 id。如果您得到 EOF(例如,用户使用来自 /dev/null 的标准输入运行程序),您将在 action 中没有确定性值,除非初始化为 '\0'

【讨论】:

  • 谢谢!我需要检查的东西太多了……当然还有更多的练习。谢谢!
【解决方案3】:

我在这里修复了你的代码:

#include <stdio.h>

    int main()
    {

      char action;

      printf("Please enter 'i' to work with integers or 'd' to work with decimals.\n\n");


      scanf("%c", &action);
       while (action != 'i' && action != 'd') // here the loop will stop if action is 'i' or 'd'
       {
         printf("You didn't entered the right command. Please try again (i/d)\n");
         scanf("\n%c", &action);// here to deal with '\n'
       }
     }

【讨论】:

  • 您可以通过使用" %c"%c 之前有一个空格)作为格式字符串来“更好地”修复它。这会跳过任何前导空格,并在第二个 scanf() 跳过等待读取的换行符。您还应该始终检查scanf() 是否报告成功;例如,如果有人从/dev/null 提供此代码输入,则循环将运行很长时间。
  • @JonathanLeffler 是的,你是对的。 "\n%c" 也可以和 "%c" 一样好用。
  • @LidongGuo at Jonathan Leffler 耶稣,当我在这里发布问题时,我会在这里和那里学习小技巧吗?
  • @Confiture 你的实际意思是什么?我不明白。我英语不好
  • @Confiture 我的 auwser 让你心烦意乱?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-17
  • 1970-01-01
  • 1970-01-01
  • 2022-01-18
  • 2012-08-10
  • 2021-07-01
相关资源
最近更新 更多