I'm new here and fairly new to c++. Not sure if this forum is exclusivly for students because I am not one, just learning it for fun. I read the "read me" on flushing the input stream but it seemed rather complicated. What's happening is if the correct color is chosen the first time everything works great but if your choose wrong and are asked to choose again it somehow cycles through the loop as if it recieved input even though it hasn't. Is there a simple way to flush the input or is there something I can do to clean up my code so I don't have that problem in the first place?

int main()
{
string sentance;
string black="color";
string color="none";
do
{
cout<<"Enter a sentance using your favorite color\n\n";
getline(cin,sentance);
if(sentance.find("black")!=string::npos)
   color="black";
if (color=="none")
   {
   cout<<"I don't like that color, can you call it a different one?\n";
   cin>>color;
   }
cout<<"Color is:\t"<<color<<"\n";
color="none";
}
while (black=="color");
return 0;
}

Recommended Answers

All 4 Replies

unfortunately, there is no portable way to discard unread characters from a stdio input stream. a language library technique would not necessarily be sufficient for this since unread characters can also accumulate in buffers other than the c++ streambuf (OS-level input buffers). to actively discard typed-ahead input (perhaps in anticipation of issuing a critical prompt), you'll have to use a system-specific technique; eg. for UNIX use tcflush.(You may also be able to use the curses flushinp function.)

you can consume the rest of a partially-read line with a simple code fragment like

while((c = getchar()) != '\n' && c != EOF)  /* discard */ ;

or you could use the ignore member function.

most often what you would want to do is consume whitespace characters remaining in the stream buffer *before* the next non-whitespace. for this, use the manipulator std::ws. for example, in your code, modifying the line getline(cin,sentance); to getline(cin>>ws,sentance); would be sufficient.

note: the problem of lookahead in a stream buffer is a difficult one, and ws is very different from other extractors. unlike other input mechanisms, the ws manipulator is not required to construct the sentry object prior to input. ws is also not a member function, so the exception policy for istream member functions does not apply to ws. this is different from the rest of extractors and all the other input functions (ws will not cause a tied stream to be flushed before extraction, it doesn't check the stream's exceptions or catch exceptions thrown during input, and it doesn't affect the stream's gcount). this was an active issue in 2003 and will be resolved in c++0x.

thanks, the

getline(cin>>ws,sentance);

seems to be the quickest and most painless way to fix the problem. In what instance specifically will this not work?

> In what instance specifically will this not work?
if your intent is only to discard whitespace characters from the stream, this will always work. that is the reason why the standard provides ws manipulator. and as it is difficult for a normal programmer to write this correctly, you should always prefer this over anything else.

however, if i want to read leading whitespace characters in the next line, this would not be suitable; it will skip over them. for this i would use the ignore member function of istream.

the problems i mentioned in the earlier post exist because the ws manipulator has to do a look ahead in the buffer, extract and remove characters till the next character that is left is a non-whitespace character. lookahead is notoriously difficult to implement correctly in a portable manner. the only lookahead that is guaranteed by the standard to succeed is the *one* character look ahead provided by streambuf::underflow. this is a protected virtual funcion of streambuf and you can not call it in a standard streambuf (you need to derive your own class). and all that extra leeway given to the ws maniplator is because of this.

While all true, I think your input paradigm is broken.

how you do it matters
Whenever you ask for input from the user what you expect him (or her) to do is type some number of characters and press the ENTER key. That's what getline( cin, s ); is for. It reads and stores each character until either the newline (ENTER) character or the end of the input stream is encountered.

However, the istream class is not designed for that kind of input. (Notice how the getline() function is not a member function?) The class is designed for whitespace delimited tokenizing. What that means is that it takes a sequence of "words" (lists of characters not containing whitespace) and attempts to convert them to the target data type.

For example, the input string

Hello  12     -3.141592   A

   "What up?"

has six tokens in it. You can read it using cin (or any other istream) thusly:

string hello, what, up;
int twelve;
double neg_pi;
char c;
cin >> hello >> twelve >> neg_pi >> c >> what >> up;

Notice how the "What up?" is two strings? (There's a space in the middle.) Whitespace is any sequence of characters made up of spaces, tabs, and newlines. You could have twelve new lines between the "What and up?" and it would read the same.

This is roughly equivalent to the C scanf( stdin, "%s%d%lf%c%s%s", &hello, &twelve, &neg_pi, &c, &what, &up ); except that it is much better suited to error handling than scanf() ever was. In both cases, however, you had to know what type of thing you were attempting to read. If I had asked for an integer first, both methods would have choked on "Hello" and nothing else would have been read.

application
So, now that we know that stuff, we can look over the code and realize that saying cin >> color; breaks the user-input assumption. The user still types a color name (well, hopefully), and presses ENTER. This code reads only the first "word" of what the user typed and stops there. If the user just hits ENTER nothing happens, because the input is still waiting for the user to type something. This is the second flaw, the user is not allowed to goof up in a specific way. Both of these problems appear to the poor sap using the program as inconsistent behavior --even though it is doing exactly what was asked of it.

To avoid these problems, always* use getline() when getting input from the user. If necessary, convert the inputted string after the user hits ENTER.

*There are times when you can do differently, but you must know enough to know when these times occur.

#include <iostream>
#include <sstream>

int main() {

  std::string s;
  int i;
  getline( std::cin, s );
  if (!(std::istringstream( s ) >> i))
    std::cout << '"' << s << "\" is not an integer" << std::endl;

  return EXIT_SUCCESS;
  }

Hope this helps.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.