【问题标题】:entering a string into scanf with a while < 0 condition causes infinite loop在 while < 0 条件下将字符串输入 scanf 会导致无限循环
【发布时间】:2016-11-13 16:41:11
【问题描述】:

我有一个“分钟”变量,我希望用户输入一个正数。

int main(void)
{
    float minutes;
    minutes = -1;
    printf("Find out how many bottles worth of water your showers use!\n");
    printf("How many minutes do you spend in the shower? ");
    scanf("%f", &minutes);
    while(minutes < 0)
    {
        printf("Please enter a positive number: ");
        scanf("%f", &minutes);
    }
}

它按预期用于数字。如果 minutes >= 0,它接受它,如果 minutes

printf("Please enter a positive number: "); 

并且永远不会给我输入新值的机会。为什么会这样,我该如何解决?谢谢!

【问题讨论】:

  • 你打算用这个程序做什么?负分钟和正分钟是什么意思?
  • 请注意,scanf 首先并不是获取输入的最安全方式,尤其是当您想要处理不同的输入可能性时。查看接受的答案here
  • 为什么标题的措辞好像这是 C 中的一个错误?

标签: c string while-loop


【解决方案1】:

如果您不输入数值,您输入的任何内容都会保留在输入缓冲区中。您可以通过读取scanf 的返回值来检查这一点,它告诉您读取的项目数。如果为 0,则可以使用getchar 读取字符,直到下一个换行符刷新缓冲区。

int main(void)
{
    int rval, c;
    float minutes;
    minutes = -1;
    printf("Find out how many bottles worth of water your showers use!\n");
    printf("How many minutes do you spend in the shower? ");
    rval = scanf("%f", &minutes);
    if (rval == 0) {
        while (((c = getchar()) != '\n') && (c != EOF));
    }
    while(minutes < 0)
    {
        printf("Please enter a positive number: ");
        rval = scanf("%f", &minutes);
        if (rval == 0) {
            while (((c = getchar()) != '\n') && (c != EOF));
        }
    }
}

【讨论】:

  • 第一遍在哪里声明和设置'rval'?
  • @user3078414 错过了那里的复制/粘贴。固定。
  • 很好的解决方案。 +1 使用 getchar 这是符合 POSIX 的清除缓冲区的方式
  • 您还必须在第一个scanf 调用中设置rval,对吧?
  • @thedouglenz 对。固定。
【解决方案2】:

%f 转换说明符告诉scanf 在看到不属于合法浮点常量的字符(即,不是数字、小数点、或签名)。那个坏字符留在输入流中,所以下一次调用scanf 失败,下一个,下一个,等等。

您应该始终检查 scanf 的返回值 - 它会告诉您从输入流中成功读取和分配了多少项目。在这种情况下,您期望的是单个项目,因此您应该获得返回值 1。如果您获得返回值 0,则意味着输入不是正确的浮点值,并且错误的输入必须以某种方式被清除。这是一种可能的解决方案:

if ( scanf( "%f", &minutes ) == 1 )
{
  // process minutes as normal
}
else
{
  // clear everything up to the next whitespace character
  while ( !isspace( getchar() ) )
    ; // empty loop 
}

唯一的问题是scanf有点笨,如果你输入类似123fgh的东西,它会转换并分配123,同时将fgh留在输入流中;您可能希望完全拒绝整个输入。

一种解决方案是将输入读取为文本,然后使用strtod 进行转换:

char buffer[BUFSIZE]; // where BUFSIZE is large enough to handle expected input
...
if ( fgets( buffer, sizeof buffer, stdin ) )
{
  char *chk; // chk will point to the first character *not* converted; if
             // it's anything other than whitespace or the string terminator,
             // then the input was not a valid floating-point value.
  double tmp = strtod( buffer, &chk );
  if ( isspace( *chk ) || *chk == 0 )
  {
    minutes = tmp;
  }
  else
  {
    // input was not a proper floating point value
  }
}

这样做的好处是不会在输入流中留下废话。

【讨论】:

  • 注意:此代码将接受像"123 abc" 这样的输入作为有效输入。然而使用fgets() 是一个好方法。
猜你喜欢
  • 2016-06-05
  • 1970-01-01
  • 1970-01-01
  • 2016-02-14
  • 2015-12-27
  • 2014-06-18
  • 2013-12-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多