Thread: Stuck on clearing the input buffer

  1. #1
    Registered User
    Join Date
    Sep 2017
    Posts
    93

    Stuck on clearing the input buffer

    I'm using the while((c = getchar()) != '\n' && c != EOF); method but if it's called, it goes into an infinite loop.

    If the character array goes over 10, including '\n', it gets stuck in an infinite loop.

    Here's the code in totality:

    Code:
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    
    static void clearInputBuffer() {
        short int clear;
        
        while((clear = getchar()) != '\n' && clear != EOF);
        
        return;
    }
    
    
    static int nonIntDetector(char *input, unsigned int stringLength) {
        short int inputCounter, intCounter, nonIntDetect, intDetect;
        char Numbers[10] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'};
        
        nonIntDetect = 0;
        intDetect = 0;
        
        for(inputCounter = 0; inputCounter < stringLength; inputCounter++)
            for(intCounter = 0; intCounter < 10; intCounter++) {
                if(input[inputCounter] == Numbers[intCounter]) {
                    intDetect++;
                    break;
                }
                if(intDetect != inputCounter) {
                    nonIntDetect = 1;
                    
                    puts("Numbers only, please.");
                    
                    goto nestedLoopBreak;
                }
        }
        nestedLoopBreak:
        
        return nonIntDetect;
    }
    
    
    int main() {
        short int playAgain, loopChecker, randomNumber, intInput;
        char userInput[64], anotherGame[16];
        
        loopChecker = 1;
        
        puts("Random number guessing game.");
        
        do {
            randomNumber = arc4random_uniform(101);
            do {
                do {
                    printf("Enter your guess: ");
                    fgets(userInput, sizeof(userInput), stdin);
                    
                    if(strlen(userInput) > 10) {
                        
                        clearInputBuffer();
                        
                        continue;
                    }
                }
                while(nonIntDetector(userInput, strlen(userInput)));
            
                intInput = atoi(userInput);
            
                if(intInput > randomNumber)
                    puts("Too High.");
                
                else if(intInput < randomNumber)
                    puts("Too low.");
            }
            while(intInput != randomNumber);
        
            puts("You win!");
            
            do {
                do {
                    puts("Another game?");
                    puts("1. Yes, 2. No");
            
                    fgets(anotherGame, sizeof(anotherGame), stdin);
                }
                while(nonIntDetector(anotherGame, strlen(anotherGame)));
            
                playAgain = atoi(anotherGame);
            
                if(playAgain == 2) {
                    playAgain = 0;
                    loopChecker = 0;
                    continue;
                }
                else if(playAgain == 1)
                    loopChecker = 0;
            }
            while(loopChecker && puts("Invalid option."));
        }
        while(playAgain == 1);
        
        return 0;
    }

  2. #2
    Programming Wraith GReaper's Avatar
    Join Date
    Apr 2009
    Location
    Greece
    Posts
    2,728
    If you're using fgets everywhere with sufficiently large buffers, you don't need to do that. It isn't going into an infinite loop, it just finds no newline in the stream and waits for the next one. Also, I don't know whether that could be a problem or not, but getchar() returns an int, not a short.
    Devoted my life to programming...

  3. #3
    Registered User
    Join Date
    Jun 2011
    Posts
    4,509
    Code:
    char userInput[64]
    
    // ...
    
    fgets(userInput, sizeof(userInput), stdin);
    
    if(strlen(userInput) > 10) {
        // ...
    If the second argument to fgets was 10, and the user entered more characters than this, the rest of the input would remain on the buffer and have to be removed. This seems to be what you're expecting.

    However, you're telling fgets to read up to 63 characters, so as long as you enter less than this, there's no need to clear the input buffer. What you're experiencing is not an infinite loop, but the "while" loop in "clearInputBuffer()" waiting for another newline since the previous one has already been read.

    My suggesting would be to create your own "get string" function, and to use something like "strchr" in conjunction with "fgets" to remove the newline, if present - if the newline is not present (which likely means there is more input waiting), you can take further action as necessary.

  4. #4
    Registered User
    Join Date
    Sep 2017
    Posts
    93
    I'll have to give that a shot.

    IIRC, if you use fgets and stdin goes over the fgets buffer, the excess characters stay in stdin and are read when another call to fgets is executed.

    That's why I'm attempting to clear the buffer. I actually only want a 16 (including \n) buffer.

  5. #5
    Registered User
    Join Date
    Sep 2017
    Posts
    93
    Also, I know using goto is frowned upon but I've read where situations like nested loops are acceptable.

  6. #6
    Registered User
    Join Date
    Sep 2017
    Posts
    93
    Like this:

    Stuck on clearing the input buffer-screen-shot-2017-12-20-12-53-59-pm-jpg

  7. #7
    Registered User
    Join Date
    Jun 2011
    Posts
    4,509
    Quote Originally Posted by ImageJPEG View Post
    IIRC, if you use fgets and stdin goes over the fgets buffer, the excess characters stay in stdin and are read when another call to fgets is executed.
    Yes, or any other input command.

    Quote Originally Posted by ImageJPEG View Post
    That's why I'm attempting to clear the buffer. I actually only want a 16 (including \n) buffer.
    Then that's the size you need to pass to fgets. As it stands, you're giving it sizeof(userInput) which is 64.

  8. #8
    Registered User
    Join Date
    Jun 2011
    Posts
    4,509
    Quote Originally Posted by ImageJPEG View Post
    Also, I know using goto is frowned upon but I've read where situations like nested loops are acceptable.
    That can be argued, yes, but in many cases you can avoid using goto by carefully planning and restructuring your logic to avoid heavily nested loops.

  9. #9
    Registered User
    Join Date
    Dec 2017
    Posts
    627
    Quote Originally Posted by ImageJPEG View Post
    Also, I know using goto is frowned upon but I've read where situations like nested loops are acceptable.
    You can easily get rid of the goto.
    Code:
    static int nonIntDetector(char *input, unsigned int stringLength) {
        short int inputCounter, intCounter;
        char Numbers[] = "0123456789";
         
        for(inputCounter = 0; inputCounter < stringLength; inputCounter++)
            for(intCounter = 0; intCounter < 10; intCounter++) {
                if(input[inputCounter] == Numbers[intCounter])
                    break;
                if(intDetect != inputCounter) {
                    puts("Numbers only, please.");
                    return 1;
                }
        }
         
        return 0;
    }
    Although we would probably write such a routine more like this (I've switched the sense of the test) :
    Code:
    int isNumeric(const char *str) {
        while (*str != '\0')
            if (!isdigit(*str))  // include <ctype.h>
                return 0;
        return 1;
    }
    Or if you want to allow spaces before and after, then:
    Code:
    int isNumeric(const char *str)  {
        while (isspace(*str)) str++;  // skip spaces before digits
        if (*str == '\0') return 0;   // was all spaces, not numeric
        while (isdigit(*str)) str++;  // skip digits
        while (isspace(*str)) str++;  // skip spaces after digits
        return *str == '\0';          // if we reached the end, it was numeric
    }
    The world hangs on a thin thread, and that is the psyche of man. - Carl Jung

  10. #10
    Registered User
    Join Date
    Sep 2017
    Posts
    93
    Wow, I feel really dumb not using return 1 :/

  11. #11
    Registered User
    Join Date
    Sep 2017
    Posts
    93
    Also, so I don't have to keep posting my modified code:

    GitHub - e14tech/number_guess: A random number guessing game

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Clearing c++ input buffer
    By mramazing in forum C++ Programming
    Replies: 4
    Last Post: 11-08-2007, 11:05 AM
  2. Clearing the input buffer
    By caduardo21 in forum C Programming
    Replies: 1
    Last Post: 05-14-2005, 08:40 PM
  3. Clearing the Input buffer
    By Brain Cell in forum C Programming
    Replies: 5
    Last Post: 03-21-2004, 12:08 PM
  4. Clearing input buffer after using getch()
    By milkydoo in forum C++ Programming
    Replies: 3
    Last Post: 07-21-2003, 11:04 PM
  5. text input buffer clearing
    By red_Marvin in forum C++ Programming
    Replies: 4
    Last Post: 03-20-2003, 03:17 PM

Tags for this Thread