【问题标题】:Loop until user input is correct in C循环直到用户输入在 C 中正确
【发布时间】:2021-11-19 19:28:27
【问题描述】:

我编写了一个简单的程序来显示前 n 个素数,其中 n 由用户输入。到目前为止,如果用户写入一个整数,它执行得很好。

但是,如果输入不是整数(primes(input) != 1),我希望程序继续要求用户提供有效输入。

我尝试创建一个循环(参见代码)来执行此操作,但程序进入了一个无限循环。

例如,当用户输入一个字母时,程序会无限显示“你想显示多少 n 个第一个素数?”直到我退出。由于某种原因,循环中的 scanf 被忽略了。

各种来源给了我不同的解释,包括缓冲区问题。

发生这种无限循环的确切原因是什么?在输入正确之前,让程序尽可能多地给用户的最佳方法是什么?

代码如下:

#include <stdio.h>

int primes(int input);

int main(void)
{

  int input;
  
  printf("How many n first primes do you want to display? ");
  scanf("%d", &input);

    while(primes(input) != 1)
    {
    printf("How many n first primes do you want to display? ");
    scanf("%d", &input);
    }

  return 0;
}

int primes(int input)
{
  
  int count1 = 0, count2 = 0, b = 1, n = 2;
  
  if(input>=1) 
  {

      while (count1 < input)  
      { 
        b = 1;
        count2 = 0;
        while (b <= n)
        {
        
          if (n%b == 0)
          {

        count2++;
       
          }
         
          b++;
        
        }   
        
        if(count2 == 2)   
        {
        
          printf("%d\n",n);
          count1++;
         
        }
         
        n++;
          
      }

  return 1;
  
  }

  return 0;
              
}   

【问题讨论】:

  • 关键是检查scanfreturn值。
  • 当用户输入错误数据时,它会一直保留在标准输入中,直到您使用它。
  • 如果你想从用户那里读取一个简单的整数,使用scanf。但是,如果您想从用户那里读取整数并在用户键入整数以外的内容时执行智能操作,则不要使用scanf。就这么简单。 scanf 不适合这份工作。你可以花三个小时解决一半的问题,但用户仍然可以输入让你搞砸的病态输入。相反,花一小时学习how to read input using something other than scanf,你可以做得更好。
  • 另见this very similar question。 TL;DR:利用fgets()strtol(),当用户输入的长度超过允许的最大行数时,不要忘记丢弃未读字符。

标签: c loops input scanf infinite-loop


【解决方案1】:

这真的取决于你的要求。

最简单的方法是检查scanf 的返回值。基本上是这样完成的:

if(scanf("%d", &input) != 1) {
    // Code for input failure
}

但是,以上内容将接受“7asdf”,这可能是可取的,也可能不是可取的。它还可以接受前导空格,例如“7”。

如果您想要更细粒度的控制,您可以随时读取一行,然后手动解析它。以下是如何完成的一个想法:

char buf[100];
if( !fgets(buf, sizeof buf, stdin)) { // Read one line as input
    // Handle input error
}

buffer[strcspn(buffer, "\n")] = 0;  // Remove newline character because fgets leaves it there

int len = strlen(buffer);

for(int i=0; i<len; i++) {
    if( !isdigit((unsigned char)buffer[i]) ) {
        // Handle error
    }
}

上述代码不接受除数字以外的任何其他字符。例如,它会在前导或尾随空白处失败。

【讨论】:

    猜你喜欢
    • 2021-07-16
    • 2011-06-27
    • 2017-02-15
    • 2017-01-24
    • 2015-03-11
    • 2014-12-17
    • 1970-01-01
    • 2014-04-12
    • 1970-01-01
    相关资源
    最近更新 更多