954,505 Members — Technology Publication meets Social Media
Username:
Password:
Lost login information?
Have something to say? Contribute New Article Reply to this Article

"Flushing" the input stream

When you want to remove extraneous characters from an input stream in C++, it's usually because you mixed formatted and unformatted input methods. The formatted method would leave a newline in the stream and the unformatted method would consume it and terminate successfully, but fail completely to do what you wanted.

#include <iostream>

int main()
{
  std::cout<<"Enter the letter A: ";
  std::cin.get();
  std::cout<<"Enter the letter B: ";
  std::cin.get();
  std::cout<<"Too late, you can't type anymore\n";
}

Often this question stems from another question, which is how to pause a program before it terminates. Using cin.get() works only when there are no characters left in the stream. The instant you throw a cin>> foo; in the code, suddenly the solution fails. You need to clear out any leftover characters from the stream before it'll work again.

So how do you fix the problem? The good news is that unless you want to get picky, it's as simple as a loop:

#include <istream>

void ignore_line ( std::istream& in )
{
  char ch;

  while ( in.get ( ch ) && ch != '\n' )
    ;
}

This loop simply reads characters until end-of-file or a newline is read. It's generally assumed that interactive input in C++ is line-oriented and you're guaranteed to have a clean buffer after reading a newline. While that's not true (input doesn't have to be line-oriented), it's wide spread enough that we can assume it for the purposes of this thread.

So what's wrong with this approach? Nothing. In fact, this is about as good as it gets unless you want to dig down and fix the subtle problems. But before we look at the problems, here's an alternative solution that does the same thing in a different way:

#include <ios>
#include <istream>
#include <limits>

void ignore_line ( std::istream& in )
{
  in.ignore ( std::numeric_limits<std::streamsize>::max(), '\n' );
}

The ignore member function of std::istream will read and discard up to N characters or until a delimiter. In the above example, N is represented by the largest value of the streamsize data type, and the delimiter is a newline. It works equally well with just a large value (80 is common):

in.ignore ( 80, '\n' );

However, the streamsize data type is more likely to be an accurate representation of the size of the buffer that the stream is using, and it's more likely to work all of the time. This is the solution that I recommend.[author's note]
If you don't care about the advanced stuff and the above solves your problem, you can stop reading here.
[/author's note]

So what's wrong with this? There are two notable problems. The first is easy to fix, and it stems from the fact that istream isn't very flexible. istream is actually a typedef for basic_istream. If you want a wide stream to work with ignore_line, you're SOL with istream. So the trick is to use basic_istream<> instead:

#include <ios>
#include <istream>
#include <limits>

template <typename CharT>
void ignore_line ( std::basic_istream<CharT>& in )
{
  in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
}

Now ignore_line is a template function that will derive the type of characters that the stream contains from the first argument. You can pass any stream that derives from or specializes basic_istream, and the problem is gone. Instead of just '\n', it's a good idea to use widen on the literal so that it will be properly converted to a wider type if necessary. Nice and easy.

The second problem is harder. Much harder. It's harder because standard iostreams seem to block your way at every turn with lack of portability or undesired features. In fact, it's impossible to completely fix the problem. The problem is that the behavior is different depending on the contents of the stream. For example:

#include <iostream>
#include <ios>
#include <istream>
#include <limits>

template <typename CharT>
void ignore_line ( std::basic_istream<CharT>& in )
{
  in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
}

int main()
{
  std::cout<<"First input: ";
  std::cin.get();
  std::cout<<"Clearing cin.\n";
  std::cin.clear();
  ignore_line ( std::cin );
  std::cout<<"All done.\n";
}

Run this program three times:

Input: "asdf"
Output: The program finishes without any more input from you.

Input: Just hit Enter
Output: The program waits for you to hit Enter one more time.

Input: Signal EOF
Output: The program waits for you to hit Enter one more time.

The problem is that the stream is empty. If you hit Enter immediately, a newline is placed on the stream and consumed by cin.get. Likewise with signaling EOF. At that point there's nothing left in the stream and cin.ignore stops everything until you type more characters. This is because cin.ignore is a blocking read. If there's nothing to read, it waits.

What we'd like it to do is not block for any of those three cases. The good news is that the iostream library supports some possible solutions. The bad news is that these are dead ends. Here are two common ones:The sync member function
The istream class supports a member function called sync. Why it has such a function is under debate, because nobody can agree on what it should be doing. Even Bjarne Stroustrup himself incorrectly stated that it discards all characters in the stream:

#include <iostream>

int main()
{
  std::cout<<"First input: ";
  std::cin.get();
  std::cout<<"Clearing cin.\n";
  std::cin.clear();
  std::cin.sync();
  std::cout<<"All done.\n";
}

When this works, it works beautifully. The bad news is that the C++ standard doesn't require sync to do anything like discarding extraneous characters. This solution is non-portable.The in_avail member function
The next step is to look at the in_avail member function of istream's stream buffer. At first glance it looks like this member function will tell you how many characters are in the stream, and if it returns 0, you can refrain from calling ignore:

#include <iostream>
#include <ios>
#include <istream>
#include <limits>

template <typename CharT>
void ignore_line ( std::basic_istream<CharT>& in )
{
  if ( in.rdbuf()->in_avail() > 0 )
    in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
}

int main()
{
  std::cout<<"First input: ";
  std::cin.get();
  std::cout<<"Clearing cin.\n";
  std::cin.clear();
  ignore_line ( std::cin );
  std::cout<<"All done.\n";
}

As with sync, when this works, it works great. But once again, the standard raises a wall by saying that in_avail isn't required to give you an accurate representation of the characters in the stream. In fact, some popular implementations have a strictly conforming in_avail that always returns 0. Not very useful. Now we have to get creative.The putback member function

#include <iostream>
#include <ios>
#include <istream>
#include <limits>

template <typename CharT>
void ignore_line ( std::basic_istream<CharT>& in )
{
  if ( !in.putback ( in.widen ( '\n' ) ) )
    in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
  else
    in.ignore();
}

int main()
{
  std::cout<<"First input: ";
  std::cin.get();
  std::cout<<"Clearing cin.\n";
  std::cin.clear();
  ignore_line ( std::cin );
  std::cout<<"All done.\n";
}

This looks very promising because at first glance, it seems that you can attempt to push back a newline. If the operation fails, the last read character wasn't a newline and you're free to call ignore without blocking. If the operation succeeds, the newline is back and you can remove it with a single character ignore.

Sadly, it doesn't work. putback isn't not required to do any of this predictably, which raises the question of why it's even available. :icon_rolleyes:

But putback actually takes us close to a solution that seems plausible enough to work most of the time. Instead of relying on putback to fail or not, we can guarantee that the last read character is put back by using the sungetc member function of the stream's buffer. The trick is to unget the last character, then read it again and test it against a newline:

#include <iostream>
#include <ios>
#include <istream>
#include <limits>

template <typename CharT>
void ignore_line ( std::basic_istream<CharT>& in )
{
  if ( in.rdbuf()->sungetc() != std::char_traits<CharT>::eof()
    && in.get() != in.widen ( '\n' ) )
  {
    in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
  }
}

int main()
{
  std::cout<<"First input: ";
  std::cin.get();
  std::cout<<"Clearing cin.\n";
  std::cin.clear();
  ignore_line ( std::cin );
  std::cout<<"All done.\n";
}

The reason we use sungetc instead of istream's unget is because unget returns the stream, but sungetc returns either the character that was pushed back, or EOF. This way we can tell if the function failed or not more easily.

If sungetc fails, one of the following will be true:

1) The stream is in an error state.
2) There are no characters to unget.
3) The stream doesn't support ungetting characters.

If sungetc succeeds, there will always be a character to read and test against the newline. If that character matches a newline, then the last read character was also a newline and we don't need to call ignore. If the character doesn't match, then a full line hasn't been read and we can safely call ignore without blocking.

If the stream is in an error state, that's something the calling code has to deal with. If there are no characters to unget, then that's precisely what this solution is designed to properly handle. But, if the stream doesn't support ungetting characters, that's an issue. The ignore_line function will always fail to discard characters, so for those implementations that don't support ungetting characters, we can add a flag that forces an ignore. It's sometimes useful to know how many characters were ignored as well, so let's add that too and we have the final solution:

#include <ios>
#include <istream>
#include <limits>

template <typename CharT>
std::streamsize ignore_line (
  std::basic_istream<CharT>& in, bool always_discard = false )
{
  std::streamsize nread = 0;

  if ( always_discard
    || ( in.rdbuf()->sungetc() != std::char_traits<CharT>::eof()
    && in.get() != in.widen ( '\n' ) ) )
  {
    // The stream is good, and we haven't
    // read a full line yet, so clear it out
    in.ignore ( std::numeric_limits<std::streamsize>::max(), in.widen ( '\n' ) );
    nread = in.gcount();
  }

  return nread;
}

Just for good measure, I'll also include a manipulator that calls ignore_line and also a manipulator that uses ignore_line to pause the program. That way the unwashed masses can stop using system ( "PAUSE" ); and getch(); :

class ignoreline {
  bool _always_discard;
  mutable std::streamsize _nread;
public:
  ignoreline ( bool always_discard = false )
    : _always_discard ( always_discard ), _nread ( 0 )
  {}

  std::streamsize gcount() const { return _nread; }

  template <typename CharT>
  friend std::basic_istream<CharT>& operator>> (
    std::basic_istream<CharT>& in, const ignoreline& manip )
  {
    manip._nread = ignore_line ( in, manip._always_discard );
    return in;
  }
};

class pause {
  ignoreline _ignore;
public:
  pause ( bool always_discard = false )
    : _ignore ( always_discard )
  {}

  std::streamsize gcount() const { return _ignore.gcount(); }

  template <typename CharT>
  friend std::basic_istream<CharT>& operator>> (
    std::basic_istream<CharT>& in, const pause& manip )
  {
    if ( !( in>> manip._ignore ) )
      in.clear();

    std::cout<<"Press Enter to continue . . .";

    return in.ignore();
  }
};

Now all three cases behave identically:

int main()
{
  std::cout<<"First input: ";
  std::cin.get();
  std::cout<<"Clearing cin.\n";
  std::cin>> ignoreline();
  std::cout<<"All done.\n";
  std::cin>> pause();
}

And the moral of the story is: It's never as simple as it seems, writing portable code that does what you want is extremely difficult, and the iostream library is a huge mess.p.s. While I haven't yet discovered a portability issue with this solution in the standard, it doesn't mean that one doesn't exist. However, I'm confident enough in my ability to parse the legalese in the standard document that I don't foresee any problems presently.

This has been a public announcement from your friendly neighborhood C++ hacker. We now return you to your regularly scheduled programming.

Narue
Bad Cop
Administrator
15,460 posts since Sep 2004
Reputation Points: 6,464
Solved Threads: 1,401
 

I'd much rather read everything in as a string then convert to ints or doubles wherever necessary.

iamthwee
Posting Expert
5,950 posts since Aug 2005
Reputation Points: 1,543
Solved Threads: 439
 

>I'd much rather read everything in as a string then convert to ints or doubles wherever necessary.
You're so boring, iamthwee. Why do things the conventional way when you can flex your brainy muscles and solve a problem the hard way? :)

Narue
Bad Cop
Administrator
15,460 posts since Sep 2004
Reputation Points: 6,464
Solved Threads: 1,401
 

Well there you go, maybe this might also be better submitted as a tutorial as opposed to a random one off thread?

iamthwee
Posting Expert
5,950 posts since Aug 2005
Reputation Points: 1,543
Solved Threads: 439
 

About flush the input stream, I'll check it out, Thank you for your work.


Daniweb - Friendly online community for C++ learners with accurate tutorials.

msary80
Newbie Poster
2 posts since Dec 2007
Reputation Points: 10
Solved Threads: 0
 

Works great! Thanks so much!

faust_g
Newbie Poster
6 posts since May 2008
Reputation Points: 10
Solved Threads: 1
 

works great for windows. I saved it as ignoreline.h and use it as an include.

Doesn't work in linux. Anyone know why?

Compile time error message:

clearTheStream.cpp: In function ‘int main()’:
clearTheStream.cpp:24: error: ambiguous overload for ‘operator>>’ in ‘std::cin >> pause()’
/usr/include/c++/4.2/istream:131: note: candidates are: std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_istream<_CharT, _Traits>& (*)(std::basic_istream<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>] <near match>
/usr/include/c++/4.2/istream:135: note:                 std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_ios<_CharT, _Traits>& (*)(std::basic_ios<_CharT, _Traits>&)) [with _CharT = char, _Traits = std::char_traits<char>] <near match>
/usr/include/c++/4.2/istream:142: note:                 std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::ios_base& (*)(std::ios_base&)) [with _CharT = char, _Traits = std::char_traits<char>] <near match>
/usr/include/c++/4.2/istream:250: note:                 std::basic_istream<_CharT, _Traits>& std::basic_istream<_CharT, _Traits>::operator>>(std::basic_streambuf<_CharT, _Traits>*) [with _CharT = char, _Traits = std::char_traits<char>] <near match>
/usr/include/c++/4.2/backward/ignoreline.h:54: note:                 std::basic_istream<CharT, std::char_traits<_CharT> >& operator>>(std::basic_istream<CharT, std::char_traits<_CharT> >&, const ignoreline&) [with CharT = char]
/usr/include/c++/4.2/backward/ignoreline.h:72: note:                 std::basic_istream<CharT, std::char_traits<_CharT> >& operator>>(std::basic_istream<CharT, std::char_traits<_CharT> >&, const pause&) [with CharT = char]


What is abiguous overload? And is there a known bug with istream in linux?

iansane
Light Poster
26 posts since Mar 2008
Reputation Points: 10
Solved Threads: 0
 

after looking up ambiguous, I'm wondering if this code could or should be rewritten so it can be called as a member function instead of as cin >> pause(). Don't know, just throwing the idea out there. I don't even know how to begin doing that. I just copy and pasted but don't fully understand the above code yet.
Like I said it works in windows compiled with dev c++, just not in linux with g++.

Thanks for the code. I'll be able to use it in windows apps till I find out the problem with linux.

iansane
Light Poster
26 posts since Mar 2008
Reputation Points: 10
Solved Threads: 0
 
You're so boring, iamthwee. Why do things the conventional way when you can flex your brainy muscles and solve a problem the hard way?

Why should you complicate things while there is a easy way out, I mean C++ alone is complicated

Traicey
Posting Whiz in Training
283 posts since Mar 2008
Reputation Points: 26
Solved Threads: 19
 

looks like Naure covered a lot of bases with one class of functions which is great.

I appreciate your comedy ruotine Traicey, but if there is an easier way to be able to flush,empty,ignore (what ever you want to call it, it accomplishes the goal), would you please explain and post the code?

Again if anyone knows why I'm getting the compile error posted above when using g++ in linux (ubuntu) would you please help me out?

Thanks :-)

iansane
Light Poster
26 posts since Mar 2008
Reputation Points: 10
Solved Threads: 0
 

>Again if anyone knows why I'm getting the compile error posted above when
>using g++ in linux (ubuntu) would you please help me out?

I had nothing better to do, so I decided to screw around with the code Narue posted. You're correct in that g++ gives an error when compiling the 'pause' class. Try renaming the entire 'pause' class to something else, perhaps pause2 (in other words, do an entire find and replace with 'pause'), and it'll compile fine. I asked Narue about this on IRC, and she figured it was probably some gcc/g++ extension that was messing things up (which is obviously the only real possibility here).

John A
Vampirical Lurker
Team Colleague
7,630 posts since Apr 2006
Reputation Points: 2,240
Solved Threads: 339
 

Thank you John A and Narue.

I never would have thought of something like that since I'm a noob. I don't know enough to decide between windows, linux and the different compilers who is complying with c++ standards and who is not fully compliant. You are a real help.
Thanks for the hard work coding this and thanks for looking into my g++ problem.

iansane
Light Poster
26 posts since Mar 2008
Reputation Points: 10
Solved Threads: 0
 

> ...probably some gcc/g++ extension that was messing things up
> (which is obviously the only real possibility here).
it is not some gcc/g++ extension; it is POSIX
man pause http://node1.yo-linux.com/cgi-bin/man2html?cgi_command=pause(2 )

vijayan121
Posting Virtuoso
1,606 posts since Dec 2006
Reputation Points: 1,159
Solved Threads: 287
 

That's why Edward puts as much code as possible in namespaces. Compilers are bad about including all kinds of unexpected stuff in the standard headers, so even if you don't include unistd.h yourself, iostream or another standard header might do it for you and create a name conflict.

Radical Edward
Posting Pro
545 posts since May 2008
Reputation Points: 361
Solved Threads: 97
 

I can not find unistd.h anywhere on my system.

So let me see if I understand this.

POSIX is the linux API just like there's a Windows API.

By changing pause to pause2, we have something that complies to c++ standards, Windows API standards, and POSIX standards.

Is that how it works? I guess just learning c++ will not be enough if I want to program cross platform?

Is one or the other of the above mentioned not 100% following standards or is that just the way it works?

Sorry so many questions but I don't understand this type of issue yet. Tell me if I'm way off in my way of thinking. Is this even a standards issue or something else?

Thanks

iansane
Light Poster
26 posts since Mar 2008
Reputation Points: 10
Solved Threads: 0
 

hmm nice topic. i leart the way...thanks to all.. :)

xxxviking
Newbie Poster
19 posts since Jun 2008
Reputation Points: 8
Solved Threads: 0
 

Don't know how useful this is to anyone else, but I made a pdf set up for easy reading on my Irex Iliad digital book reader. I'm sure some of you have some Kindles or Sony Readers or whatever.

Anyway, here you go, my pdf I made of Narue's post. (By the way if you feel this is in some way a violation of your work feel free to remove it)

Attachments flush_in_stream.pdf (490.74KB)
chococrack
Junior Poster
149 posts since Oct 2008
Reputation Points: 92
Solved Threads: 16
 

C++ string and getline are your friends so get to know them well :)

// flushinput.cpp
// A test program to test flushing input specifically cin
// Last Modified: 20081208

#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
#include <exception>
#include <stdexcept>
#include <new>
using namespace std;

int main()
{
cout << "flushinput" << endl;
cout << "A test program to test flushing input specifically cin." << endl;
string input1 = "";
string input2 = "";
cout << endl;
cout << "There are 5 input tests:" << endl;
cout << "1. Type 1 or more characters and then press Enter." << endl;
cout << "2. Just hit Enter(don't type any characters, just press Enter)." << endl;
cout << "3. Signal EOF(don't type any characters, Linux - just press Ctrl+D. Windows - just press Ctrl+Z and then Enter)." << endl;
cout << "4. Type 1 or more characters and then Signal EOF and then press Enter(Windows - press Enter a second time)." << endl;
cout << "5. Type 1 or more characters and then Signal EOF twice(Windows - press Enter twice after signalling EOF twice)." << endl;
cout << endl;
cout << "Correct solution would be that the program waits for you to enter the 2nd input regardless of what you entered for the 1st input." << endl;
cout << "Incorrect solution would be that the program finishes without asking for the 2nd input." << endl;
cout << endl;
cout << "Enter 1st input: ";
getline(cin, input1);
cerr << endl;// Input tests 1 - 5: L - Linux, W - Windows		L   L   L   L   LW
cerr << "cin.bad()=" << cin.bad() << endl;// Results:			0	0	0	0	00
cerr << "cin.eof()=" << cin.eof() << endl;//					0	0	1	0	10
cerr << "cin.fail()=" << cin.fail() << endl;//					0	0	1	0	00
cerr << "cin.good()=" << cin.good() << endl;//					1	1	0	1	01
cerr << "input1.size()=" << input1.size() << "!" << endl;//		3	0	0	3	33
	if(!cin.good())// Input tests 3(Windows & Linux) & 5(Linux only) put cin into an error state.
	{
	cin.clear();// Reset the cin status flags to their default.
	}
cout << endl;
cout << "Enter 2nd input: ";
getline(cin, input2);
cout << "Program finished." << endl;
return 0;
}


There are some minor differences between Linux and Windows which I have documented. For input tests 1, 4, & 5 I used:
abc
for the 1st input.

ronjustincase
Newbie Poster
12 posts since Dec 2008
Reputation Points: 11
Solved Threads: 2
 

cout.flush ????

AHUazhu
Newbie Poster
17 posts since Dec 2008
Reputation Points: 10
Solved Threads: 2
 
cout.flush ????


This is a discussion about flush the INPUT buffer....so this is a completely pointless post, before making a suggestion at least make it a viable suggestion

Chris

Freaky_Chris
Master Poster
702 posts since Apr 2008
Reputation Points: 325
Solved Threads: 118
 

Post: Markdown Syntax: Formatting Help
You