How to fix infinite loops when user enters wrong data type in scanf()?

一笑奈何 提交于 2020-06-17 05:29:08

问题


C beginner here. For the program below, whenever the user inputs a character or a string it enters an infinite loop. How would you fix this while still using scanf? And what would be the better methods of writing this program rather than using scanf? Thanks to those who will answer.

#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;   
}

回答1:


I'd say there are just two "fixes".

  1. Retain the scanf call(s), warts and all. Carefully refrain from typing non-digits when scanf is expecting digits.

  2. Abandon scanf and use something else. We've just been discussing this tactic over at this new question.

Once you're using scanf, it's always tempting to try to "fix" it, so there's potentially a third answer lurking here, explaining how to do better, more user-friendly, more error-tolerant input while still using scanf. In my opinion, however, this is a fool's errand, a waste of time. The easy, obvious fixes for scanf's many deficiencies are themselves imperfect and have further deficiencies. You will probably spend more time trying to fix a scanf-using program than you would have spent rewriting it to not use scanf -- and you'll get overall better results (not to mention a cleaner program) with the non-scanf-using rewrite anyway.




回答2:


Using 'scanf' require the input to be formatted. Scanf has very limited ability to handle bad input. The common solution will be to use fgets/sscanf, following the structure below:

   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 ...

The fgets/sscanf will allow recovery from parsing error - the bad input line will be ignored. Depending on requirement, this might be accepted solution.




回答3:


Change

scanf("%d", &rounds);

To

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
}



回答4:


If you really like scanf, you can use getch to discard non-numeric input:

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



回答5:


C beginner here as well. Like you, I use scanf, and it can be problematic sometimes.

I've had your same problem and tried to solve it with scanf and basic stuff before finding a better solution. I've tried different solution from here but I continue to have the same problems again and again, like if I type:

  • a number followed by a character (e.g. 123a), the result is a valid number (which i don't want); the result is '123'.
  • a string of numbers and chars that begin with a number (e.g. 1a2b3), the result is still a valid number which is '1'.
  • a char at the beginning (e.g. a123) can generate infinite loop.

... and so on... I've tried do...while, only while, for... nothing.

The only solution I have found to prompt the user until he/she writes only numbers is the following, but...

NOTE: if the user type a space, the program considers only the part before it, e.g. '12 3', only 12 is considered, 3 doesn't exist... unless you want use an infinite loop like I did so, in this case, you can enter multiple numbers, check them and run your program on them all at once. e.g.: '12 23 34 45' ...

NOTE 2: this is a very basic beginner solution, I am learning, and this is just what I found with what I know. Can't do any better right now and, as I said, I didn't find any other solution that I liked the output.

NOTE 3: I use the counter to sum up all the inputs that are not numbers and store the value if it finds one. If I don't use this solution I'll end up in the case where if the first character is a number but the rest aren't, it's still valid (e.g.: '12w3' is 12, which I don't want)

#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);
  }
}

You can also put it in a function and away from the main().



来源:https://stackoverflow.com/questions/58434411/how-to-fix-infinite-loops-when-user-enters-wrong-data-type-in-scanf

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!