C: scanf did not stop in infinite while loop [duplicate]

余生长醉 提交于 2021-02-07 10:58:07

问题


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.


回答1:


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.




回答2:


#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



回答3:


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


来源:https://stackoverflow.com/questions/53474700/c-scanf-did-not-stop-in-infinite-while-loop

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