0

I want to implement a simple code to print the error message when the type of input is not an integer.

Below is a sample code.

int num;
while (1) {
    printf("Input the value of integer: ");
    int result = scanf(" %d", &num);
    if (result == 0) {
        printf("ERROR-Not an integer.\n");
    }
    else if (num < 0) {
         printf("ERROR- Not positive.\n");    
    }else{ 
        break;   
    }
}

In this code, if the value is not the integer, "scanf" will ask the number.

However, this function did not break when the input is not the integer.

Maybe the problem is the value on the buffer. "fflush" would be solution,but I don't want to use it.

Kim Rose
  • 3
  • 4
  • 1
    The leading whitespace character in `" %d"` is not needed since the `%d` conversion specifier already consumes leading whitespace characters; the only conversion specifiers that _don't_ consume leading whitespace are `%c`, `%n`, and `%[]`. – ad absurdum Nov 26 '18 at 04:26
  • The test should be `result != 1`, because the result can be negative in the case of input failure – M.M Nov 26 '18 at 04:57
  • You can get 3 results from `scanf()` — 1, 0, EOF. You report an error when you get 0, but you do nothing to fix the error, so the next attempt fails too, and will keep failing until you do something about the unwanted character(s) in the input stream. You should also detect EOF and terminate the loop. You should report errors to standard error (`stderr`) and not standard output (`stdout`) too, usually. That's what it's for, at any rate. – Jonathan Leffler Nov 26 '18 at 06:31

3 Answers3

3

The problem is you fail to empty-stdin on the matching failure case. You are looking for integer input. If the user enters anything other than an integer, a matching failure occurs. When the matching failure occurs, character extraction from stdin stops and the characters causing the matching failure are left in the input buffer (stdin here) unread -- just waiting to bite you again if you attempt to read again without clearing stdin first... If you are taking input in a loop -- well, you know what happens...

(honey... I tried to read an int and it failed, and I kept trying and it kept failing - help??)

How to fix it?

Very simply, you must empty stdin after a matching failure. You are doing much better than most -- you are checking the return, but you have one piece of the puzzle to add -- a simple function to empty_stdin() when a matching failure occurs. A very portable and very simple way is to simply extract all characters until a newline or EOF is encountered, e.g.:

void empty_stdin(void) {
    int c = getchar();

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

Putting all the pieces together in your example, you could do:

#include <stdio.h>

void empty_stdin(void) {
    int c = getchar();

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

int main (void) {
    int num;
    while (1) {
        printf("Input the value of integer: ");

        int result = scanf(" %d", &num);

        if (result == EOF) {    /* handle ctrl+d (ctrl+z on win) */
            printf (" user canceled input (manual EOF)\n");
            break;
        }
        else if (result == 0) { /* matching failure */
            printf("ERROR-Not an integer.\n");
            empty_stdin();      /* remove offending characters */
        }
        else if (num < 0) {
            printf ("ERROR- Not positive.\n");    
        }
        else        /* positive number enetered */
            break;
    }

    return 0;
}

(@David Bowling has already explained in the comments that the leading space in " %d" is unnecessary as all numeric conversions consume leading whitespace)

Example Use/Output

$ ./bin/scanf_empty
Input the value of integer: foo
ERROR-Not an integer.
Input the value of integer: -1
ERROR- Not positive.
Input the value of integer: bar
ERROR-Not an integer.
Input the value of integer: 1

Testing manual EOF case (user presses Ctrl+d (or Ctrl+z windows)

$ ./bin/scanf_empty
Input the value of integer:  user canceled input (manual EOF)

Look things over and let me know if you have further questions.

David C. Rankin
  • 81,885
  • 6
  • 58
  • 85
1
#include <stdio.h>

int main()
{
    int num;
    int result;

    while (printf("Please input an unsigned integer: "),
           (result = scanf(" %d", &num)) != 1 || num < 0 )
    {                                 //  ║          ╚══ was successful but negative
        if (result != 1) //  <════════════╝ 1 conversion was requested
             fputs("ERROR: Not an integer.\n", stderr);  // write error messages
        else fputs("ERROR: Not positive.\n", stderr);   // to stderr

        int ch;  // the following loop *) reads garbage that might be left in stdin
        while ((ch = getchar()) != '\n' && ch != EOF);  // so the next scanf() won't
    }                                                   // fail because of it.
    printf("You entered: %d\n", num);
}

*) Plan-B:

scanf("%*[^\n]");  // this scanset matches all characters except newline
getchar();        // remove the newline

*) Plan-C:

scanf("%*[^\n]");  // this scanset matches all characters except newline
scanf("%*c");     // remove the newline

Sample Dialog:

Please input an unsigned integer: foo
ERROR: Not an integer.
Please input an unsigned integer: bar
ERROR: Not an integer.
Please input an unsigned integer: -75
ERROR: Not positive.
Please input an unsigned integer: 42
You entered: 42
Swordfish
  • 12,971
  • 3
  • 21
  • 43
-1

You need to clear stdin before/after every scanf. I personally prefer before.

fseek(stdin, 0, SEEK_END);

int num;
while (1) {
    fseek(stdin, 0, SEEK_END);
    printf("Input the value of integer: ");
    int result = scanf_s(" %d", &num);
    if (result == 0) {
        printf("ERROR-Not an integer.\n");
    }
    else if (num < 0) {
        printf("ERROR- Not positive.\n");
    }
    else {
        break;
    }
}
Dark Sorrow
  • 1,681
  • 14
  • 37