Search code examples
c++getline

Issue When Clearing cin Buffer After Using cin.getline()


I am using getline (the cin.getline() one) to get a string from cin and finding an issue with a special case. If a user inputs more characters than the the streamsize argument (in this case, 50), the cin buffer holds them and puts them into the next cin call. If I use cin.clear() and cin.ignore() and the user enters in fewer characters than the streamsize argument, then the program waits for the user to press enter again before it continues. So I use strlen to check the size of the string and only use cin.clear() and cin.ignore() if the string has 50 characters. This chops off the extra characters that the user entered after the 49th character. The problem is that when the user enters exactly 49 characters, then there are no extra characters in the buffer to chop off with the cin.clear() and cin.ignore() calls and therefore the program will sit and wait for the user to press enter another time.

A couple of questions:

1) Is there a flag I can check to see if there are characters in the buffer so I can clear() and ignore() only when this flag is true?

2) Is there any other way I can call this same getline function that cuts off all characters after the streamsize argument?

Here is my code:

#include <iostream>
#include <cstring>
using namespace std;

#define SIZE 50

void getString(char*);

int main() {
    char words[SIZE];
    getString(words);
    return 0;
}

void getString(char* words) {
    cout << "Enter your string: ";
    cin.getline(words, SIZE);
    if (strlen(words) == SIZE - 1) {
        cin.clear();
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
    }
}

A sample 49 character input that would cause the issue:

abcdefghijklmnopqrstuvwxysabcdefghijklmnopqrstuvw

Erase or add one letter to see the program's normal performance.


Solution

  • You can use istream::gcount() to decide whether there are any more characters other than '\n' left in the line still.

    Here are the cases you need to think about.

    1. The return value of cin.gcount() is less than SIZE-1. In this case, there is nothing left in the line. You don't have to worry about ignoring the rest of the line.

    2. The return value of cin.gcount() is SIZE-1. This could be due to two scenarios.

      1. The user enters SIZE-2 characters followed by a newline. In this case, there is nothing left in the line. You don't have to worry about ignoring the rest of the line.

      2. The user enters SIZE or more number of characters followed by a newline. In this case, there are still some characters left in the line. You will want to ignore the rest of the line.

    3. The return value of cin.gcount() is SIZE. This can happens only when the user enteres SIZE-1 characters followed by a newline. All the characters from the line are read into the argument provided to the function. The newline character is read and discarded. You don't have to worry about ignoring the rest of the line.

    Give the above cases, the only time you have to worry about ignoring the rest of the line is when you run into case 2.2. That condition is met when cin.gcount() == SIZE-1 and strlen(words) == SIZE-1.

    void getString(char* words) {
        cout << "Enter your string: ";
        cin.getline(words, SIZE);
        if (cin.gcount() == SIZE-1 && strlen(words) == SIZE-1)
        {
            // There are characters in the stream before the \n.
            cin.clear();
            cin.ignore(numeric_limits<streamsize>::max(), '\n');
        }
    }