Why is scanf() causing infinite loop in this code?

后端 未结 16 1437
日久生厌
日久生厌 2020-11-21 06:20

I\'ve a small C-program which just reads numbers from stdin, one at each loop cycle. If the user inputs some NaN, an error should be printed to the console and the input pro

相关标签:
16条回答
  • 2020-11-21 06:53
    // all you need is to clear the buffer!
    
    #include <stdio.h>
    
    int main()
    {
        int number, p = 0, n = 0;
        char clearBuf[256]; //JG:
        while (1) {
            printf("-> ");
            if (scanf("%d", &number) == 0) {
                fgets(stdin, 256, clearBuf); //JG:
                printf("Err...\n");
                continue;
            }
    
            if (number > 0) p++;
            else if (number < 0) n++;
            else break; /* 0 given */
        }
    
        printf("Read %d positive and %d negative numbers\n", p, n);
        return 0;
    }
    
    0 讨论(0)
  • 2020-11-21 06:55

    When a non-number is entered an error occurs and the non-number is still kept in the input buffer. You should skip it. Also even this combination of symbols as for example 1a will be read at first as number 1 I think you should also skip such input.

    The program can look the following way.

    #include <stdio.h>
    #include <ctype.h>
    
    int main(void) 
    {
        int p = 0, n = 0;
    
        while (1)
        {
            char c;
            int number;
            int success;
    
            printf("-> ");
    
            success = scanf("%d%c", &number, &c);
    
            if ( success != EOF )
            {
                success = success == 2 && isspace( ( unsigned char )c );
            }
    
            if ( ( success == EOF ) || ( success && number == 0 ) ) break;
    
            if ( !success )
            {
                scanf("%*[^ \t\n]");
                clearerr(stdin);
            }
            else if ( number > 0 )
            {
                ++p;
            }
            else if ( number < n )
            {
                ++n;
            }
        }
    
        printf( "\nRead %d positive and %d negative numbers\n", p, n );
    
        return 0;
    }
    

    The program output might look like

    -> 1
    -> -1
    -> 2
    -> -2
    -> 0a
    -> -0a
    -> a0
    -> -a0
    -> 3
    -> -3
    -> 0
    
    Read 3 positive and 3 negative numbers
    
    0 讨论(0)
  • 2020-11-21 06:58

    The Solution: You need to add fflush(stdin); when 0 is returned from scanf.

    The Reason: It appears to be leaving the input char in the buffer when an error is encountered, so every time scanf is called it just keeps trying to handle the invalid character but never removing it form the buffer. When you call fflush, the input buffer(stdin) will be cleared so the invalid character will no longer be handled repeatably.

    You Program Modified: Below is your program modified with the needed change.

    #include <stdio.h>
    
    int main()
    {
        int number, p = 0, n = 0;
    
        while (1) {
            printf("-> ");
            if (scanf("%d", &number) == 0) {
                fflush(stdin);
                printf("Err...\n");
                continue;
            }
    
            if (number > 0) p++;
            else if (number < 0) n++;
            else break; /* 0 given */
        }
    
        printf("Read %d positive and %d negative numbers\n", p, n);
        return 0;
    }
    
    0 讨论(0)
  • 2020-11-21 06:59

    Rather than using scanf() and have to deal with the buffer having invalid character, use fgets() and sscanf().

    /* ... */
        printf("0 to quit -> ");
        fflush(stdout);
        while (fgets(buf, sizeof buf, stdin)) {
          if (sscanf(buf, "%d", &number) != 1) {
            fprintf(stderr, "Err...\n");
          } else {
            work(number);
          }
          printf("0 to quit -> ");
          fflush(stdout);
        }
    /* ... */
    
    0 讨论(0)
  • 2020-11-21 06:59

    I had the same problem, and I found a somewhat hacky solution. I use fgets() to read the input and then feed that to sscanf(). This is not a bad fix for the infinite loop problem, and with a simple for loop I tell C to search for any none numeric character. The code below won't allow inputs like 123abc.

    #include <stdio.h>
    #include <ctype.h>
    #include <string.h>
    
    int main(int argc, const char * argv[]) {
    
        char line[10];
        int loop, arrayLength, number, nan;
        arrayLength = sizeof(line) / sizeof(char);
        do {
            nan = 0;
            printf("Please enter a number:\n");
            fgets(line, arrayLength, stdin);
            for(loop = 0; loop < arrayLength; loop++) { // search for any none numeric charcter inisde the line array
                if(line[loop] == '\n') { // stop the search if there is a carrage return
                    break;
                }
                if((line[0] == '-' || line[0] == '+') && loop == 0) { // Exculude the sign charcters infront of numbers so the program can accept both negative and positive numbers
                    continue;
                }
                if(!isdigit(line[loop])) { // if there is a none numeric character then add one to nan and break the loop
                    nan++;
                    break;
                }
            }
        } while(nan || strlen(line) == 1); // check if there is any NaN or the user has just hit enter
        sscanf(line, "%d", &number);
        printf("You enterd number %d\n", number);
        return 0;
    }
    
    0 讨论(0)
  • 2020-11-21 07:03

    Due to the problems with scanf pointed out by the other answers, you should really consider using another approach. I've always found scanf way too limited for any serious input reading and processing. It's a better idea to just read whole lines in with fgets and then working on them with functions like strtok and strtol (which BTW will correctly parse integers and tell you exactly where the invalid characters begin).

    0 讨论(0)
提交回复
热议问题