0

I am trying to see if user enters 3 correct input. If not the loop ask for input again and again until they correct it correctly.

#include <stdio.h>
int main(void) {

        int num1,num2;
        char str;
        int check;

        printf("Enter : ");
        check = scanf("%d,%d, %c", &num1, &num2, &str);

        while (check != 3) {

                 printf("Enter : ");
                 check = scanf("%d,%d, %c", &num1, &num2, &str);
        }


}

Let's say if I entera, 5.4, c we get an infinite loop. Why is it giving an infinite loop?

Aamir John
  • 75
  • 2
  • 4
  • 6
  • 3
    Because the `scanf` does not consume the input if it does not match. So your code is continuously trying to parse the same input (which will never succeed). – kaylum Nov 18 '15 at 02:11
  • you initialize main to be `int main(void)` and then you dont return a value from main? Where's your `return 0`? – TheQAGuy Nov 18 '15 at 02:12
  • why don't you use `return` function – orvi Nov 18 '15 at 02:20
  • 2
    [Why is scanf() causing infinite loop in this code?](https://stackoverflow.com/questions/1716013/why-is-scanf-causing-infinite-loop-in-this-code) – kaylum Nov 18 '15 at 02:25
  • @JackWilliams: Technically `main()` doesn't need to explicitly return. A return value of `0` is implied, since C99. – Crowman Nov 18 '15 at 02:26
  • Instead, use `fgets()` to read the line and then parse it, maybe with `sscanf()` – chux - Reinstate Monica Nov 18 '15 at 02:51
  • You could simplify your code by moving the first `printf` and `check =` to be inside the loop, and giving an initial value such as `int check = 0;` (or using a do...while loop) – M.M Nov 18 '15 at 04:07

2 Answers2

1

There are far more ways to incorrectly use scanf in a loop that proper ones. The primary issue (aside from input or matching failures that are explained in the man page), is failing to empty the input buffer (stdin when reading from a terminal) after a failed conversion. (There is also the issue that the user must enter something.) When a user enters text and presses [Enter] a newline ('\n') is generated and placed in the input buffer to mark the end of line. When you enter a, 5.4, c, 'a' is fine, but 5.4 is not an int and the processing fails:

If processing of a directive fails, no further input is read, and scanf() returns.

When scanf returns, it leaves the remaining characters in stdin and you loop and attempt to read again. scanf attempts to read what is left in stdin, processing again fails, and the loop continues endlessly.

In this situation the only way to prevent the indefinite loop is to manually empty the input buffer after you call to scanf. Something simple will do:

int c;
...
while (...) {
    scanf (...)
    while ((c = getchar()) != '\n' && c != EOF) {}
}

This will insure you start with an empty buffer on the next iteration. For example:

#include <stdio.h>

int main (void) {

    int num1 ,num2, c;
    char str;

    while (printf ("\nEnter : ") && 
           scanf (" %d, %d, %c%*c", &num1, &num2, &str) != 3) {
        printf ("error: invalid input, required: 'int, int, char'\n");

        /* empty remaining chars from input buffer */
        while ((c = getchar()) != '\n' && c != EOF) {}
    }

    printf ("\n num1 : %d\n num2 : %d\n str  : %c\n\n", num1, num2, str);

    return 0;
}

Example Use

$./bin/scanf3

Enter : a
error: invalid input, required: 'int, int, char'

Enter : a, 5.4, c
error: invalid input, required: 'int, int, char'

Enter : 10, 25
error: invalid input, required: 'int, int, char'

Enter : 10, 25, a

 num1 : 10
 num2 : 25
 str  : a

note: this does not protect against the user entering nothing (just pressing [Enter]) and the cursor just sitting there blinking as it waits for input. That is an inherent behavior of scanf, part of which is the reason that line-oriented input methods (fgets or getline) are preferable when taking input.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
-1

First time scanf() reads the character then it reads the newline (enter/whitespace character ).This character is present in the input buffer and is read by the scanf() function.

So clear the buffer before reading the new user input using fflush(stdin).

EDIT : Tested in windows VS2013.Sorry i dont have Linux. Windows and Linux define the behaviour of fflush() in different way.If you are using in Windows platform :

int main(void) {

    int num1, num2;
    char str;
    int check;

    printf("Enter : ");
    check = scanf("%d,%d, %c", &num1, &num2, &str);

    while (check != 3) {

////Flush the input buffer ////

        fflush(stdin);
        printf("Enter : ");
        check = scanf("%d,%d, %c", &num1, &num2, &str);
    }

}

EDIT : this will work in all platforms.

Another simple way is to consume the remaining read line by

while ((c = getchar()) != '\n' && c != EOF);

so now

int main(void) {

    int num1, num2;
    char str,c;
    int check;

    printf("Enter : ");
    check = scanf("%d,%d, %c", &num1, &num2, &str);

    while (check != 3) {

        ////read the remaining char ////
        while ((c = getchar()) != '\n' && c != EOF);

        printf("Enter : ");
        check = scanf("%d,%d, %c", &num1, &num2, &str);
    }
}
HRG
  • 182
  • 5
  • 16