【问题标题】:How to fix infinite loops when user enters wrong data type in scanf()?当用户在 scanf() 中输入错误的数据类型时如何修复无限循环?
【发布时间】:2020-02-14 11:31:44
【问题描述】:

这里是 C 初学者。对于下面的程序,只要用户输入一个字符或一个字符串,它就会进入一个无限循环。在仍然使用 scanf 的同时如何解决这个问题?编写这个程序而不是使用 scanf 的更好方法是什么?感谢那些愿意回答的人。

#include <stdio.h>
#include <ctype.h>

int main() {

int rounds = 5;

do {
printf("Preferred number of rounds per game. ENTER NUMBERS ONLY: ");
scanf("%d", &rounds);   
} while(isdigit(rounds) == 0);

return 0;   
}

【问题讨论】:

  • 总是检查scanf()的返回值,看看是否有错误,对于初学者来说。
  • 另外,isdigit() 在这里也不合适,除非您希望人们输入数字字符的 ascii 值。
  • 不要使用scanf()f 代表“格式化”。用户输入未格式化。
  • @AndrewHenle 同意用户输入未格式化,但不能同意 scanf 是。如果scanf 真的是为格式化输入而设计的,那么像%d %d\n%d %d 这样的格式字符串将无法读取1 2 3 41\n2\n3\n4

标签: c loops scanf infinite


【解决方案1】:

这里也是C初学者。和你一样,我使用scanf,有时会出现问题。

我遇到了同样的问题,并尝试使用scanf 和基本的东西来解决它,然后再找到更好的解决方案。 我从这里尝试了不同的解决方案,但我仍然一次又一次地遇到同样的问题,就像我输入:

  • 一个数字后跟一个字符(例如123a),结果是一个有效的数字(我不想要);结果是“123”。
  • 以数字开头的数字和字符的字符串(例如 1a2b3),结果仍然是有效数字“1”。
  • 开头的字符(例如 a123)会产生无限循环。

...等等...我试过do...while,只有whilefor...什么都没有。

我发现提示用户直到他/她只写数字的唯一解决方案如下,但是......

注意:如果用户键入一个空格,程序只考虑它之前的部分,例如'12 3',只考虑 12,3 不存在......除非你想像我一样使用无限循环,在这种情况下,你可以输入多个数字,检查它们并在它们上运行你的程序一次。例如:'12 23 34 45' ...

注意 2:这是一个非常基本的初学者解决方案,我正在学习,这正是我所知道的。现在不能做得更好,正如我所说,我没有找到任何其他我喜欢输出的解决方案。

注意 3:我使用计数器对所有非数字的输入求和,如果找到一个则存储该值。如果我不使用这个解决方案,我最终会遇到第一个字符是数字但其余不是数字的情况,它仍然有效(例如:'12w3' 是 12,我不想要)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

int main (void)
{
  while (1) // try also multiple inputs separated by space
  {
    char str[10]; // should be enough for short strings/numbers (?!)
    int strlength, num, counter;

    do
    {
      printf("Enter a number: ");
      scanf("%s", str);

      strlength = strlen(str);
      counter = 0;
      for (int i = 0; i < strlength; i++)
      {
        if (!isdigit(str[i]))
          counter++; 
      }
      if (counter != 0)
        printf("%s is not a number.\n", str);
    } while (counter != 0);

    num = atoi(str);

    printf("%d is a number. Well done!\n\n", num);
  }
}

你也可以把它放在一个函数中,远离main()

【讨论】:

    【解决方案2】:

    我想说只有两个“修复”。

    1. 保留scanf 呼叫、疣和所有。当scanf 期待数字时,请小心避免输入非数字。

    2. 放弃scanf 并使用其他东西。我们刚刚在this new question 讨论过这个策略。

    一旦您使用scanf,总是很想尝试“修复”它,因此这里可能潜伏着第三个答案,解释如何在仍然输入的同时做得更好、更友好、更容错使用scanf。然而,在我看来,这是徒劳的,浪费时间。对scanf 的许多缺陷的简单、明显的修复本身并不完美,并且还有更多缺陷。您可能会花费更多时间来尝试修复 scanf-using 程序,而不是重写它以不使用 scanf - 而且您将获得整体更好的结果(更不用说更清洁的程序)了-scanf-无论如何都使用重写。

    【讨论】:

      【解决方案3】:

      如果你真的很喜欢scanf,你可以使用getch来丢弃非数字输入:

      int rounds =  MIN_INT;
      while (scanf("%d", &rounds)) != 1)
         if (getc() == EOF) /* discard a rubbish character */
            break; // or other error-handling return
      
      // rounds is only valid if we did not break, when its value should be MIN_INT.
      // but you might need another indicator
      

      【讨论】:

        【解决方案4】:

        改变

        scanf("%d", &rounds);
        

        int ret;
        
        if ((ret = scanf(" %d", &rounds)) != 1) { // Skip over white space as well
           if (ret == EOF) break;
           scanf("%*[^\n\r]"); // Consume the rest of the line
        }
        

        【讨论】:

        • 如果获得 EOF 条件会发生什么? (并且%d 已经跳过了空格)。
        【解决方案5】:

        使用“scanf”需要格式化输入。 Scanf 处理错误输入的能力非常有限。常见的解决方案是使用 fgets/sscanf,结构如下:

           char buff[256] ;
           int rounds = 0 ;
           while ( fgets(buff, sizeof(buff), stdin) ) {
              if ( sscanf(buff, "%d", &rounds) == 1 ) {
                  // additional verification here
                  break ;
              } ;
           } ;
           // Use rounds here ...
        

        fgets/sscanf 将允许从解析错误中恢复 - 错误的输入行将被忽略。根据要求,这可能是可接受的解决方案。

        【讨论】:

          猜你喜欢
          • 2022-09-23
          • 2021-09-16
          • 2019-02-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2013-05-28
          • 1970-01-01
          相关资源
          最近更新 更多