I have to accept three numbers from the user using cin into 3 variables.
If the user enters non integers,I must reject it and ask for a new one instead of that.
So,here is my attempt:

int a,b,c;
	do{
		cin.clear();
		while(cin.get()!='\n');//remove failure bits,clear stream if wrong input
		cin>>a;
	}
	while(!cin);//while the entry isn't good
	do{
		cin.clear();
		while(cin.get()!='\n');
		cin>>b;
	}
	while(!cin);
	do{
		cin.clear();
		while(cin.get()!='\n');
		cin>>c;
	}
	while(!cin);

I expected it to work,but it takes 4 numbers instead of 3.
Why?
What is wrong?

Recommended Answers

All 27 Replies

You need to remove the redundant code and use a function:

int getInt(){
 int input = 0;
 while( !(cin >> input) ){
   cout << "\nPlease enter a valid input: ";
   cin.clear(); 
   while(cin.get() != '\n');   
 }
 return input;
}
int main(){
 int x = getInt() , y = getInt(), z = getInt();
}

But to answer your question, your ordering is wrong. See if you can figure it out.

>> I expected it to work,but it takes 4 numbers instead of 3.

No it takes an infinite number of numbers for those of us who DON'T enter numbers that need to be rejected.


[EDIT]
Someone down-rep me please. I can't believe I just posted that. I could edit it into obscurity, but I need to be punished.

To the OP, disregard my post.
[/EDIT]

commented: hehehe +13

@firstPerson,
No I still don't see why my code is wrong.

do{
	cin.clear();
	while(cin.get()!='\n');//everything will be reset here
	cin>>a;//if user enters proper input,the loop shouldn't run again
	}
while(!cin);

Can you please explain?

The problem is in line 4. The user never entered anything so there isn't anything to discard, thus your first input gets discarded. And the rest follows. That's why you should first get the input and check for failure instead of checking for failure then getting the input and so on.

The discarding happens in line 3,when the while loop is running.
After this,in line 4 user enters something and the "discarding while loop" already over now.
It must accept the number and and so
while(!cin)
is not met(i.e. cin was successful) and so the do while loop should stop.
Where am I wrong?

And also,
why does it ask for 4 inputs?Lets say the input into 1st variable is somehow successful.Now the stream is automatically cleared and no failure bits are left.So the problem boils down to the 1st case,doesn't it?

in the loop,i recommend taking the input,and checking for an error next accordingly,its more systematic,and your is a do while loop.

Let me try to redeem myself. Forget about 3 inputs versus 4 inputs. Think one input versus two inputs. Think about entering ONE number, making it a valid one, and see what you're program does.

do{
	cin.clear();
	while(cin.get()!='\n');//everything will be reset here
	cin>>a;//if user enters proper input,the loop shouldn't run again
	}
while(!cin);

All I want is one number and I'm going to give it a 9, which is valid. If the code is good, it will take a 9 and a '\n', throw out the '\n', keep the 9, and get me past the loop. here we go. I type '9', then '\n', so there's a "9\n" in the cin stream. Let's walk through the code.

Line 3 grabs the '9' and... throws it away. We're already off to a bad start.
Line 3 grabs the '\n' and... throws it away. Now I'm on line 4.

Now I type in '9' and '\n' again and a contains 9 and I'm done.

Wow,this is confusing.
Please hear out my version:

do{
	cin.clear();
	while(cin.get()!='\n');//everything will be reset here
	cin>>a;//if user enters proper input,the loop shouldn't run again
	}
while(!cin);

First the program starts.It reaches the 1st do while loop,the one above.
It enters the loop.It executes cin.clear(); and empties and throws away everything in the stream in the line while(cin.get()!='\n');.
However since nothing was in the stream at all(it is fresh)the above lines don't do anything.
Then there is cin>>a.The user enters something like '9'.
So a takes the value "9".Since the input was successful,the stream is cleared out and no failure bits are set.
Then it goes to the while condition.while(!cin);
The condition is naturally not met as cin was successful.
So the do block isn't run again.
Now things are still fresh and new in the input stream because there is nothing in it.
Now there are 2 more such do while block after this,and similar things have to happen thus reading into 3 variables successfully.

Where am I wrong in my try?

Please hear out my version:

do{
	cin.clear();
	while(cin.get()!='\n');//everything will be reset here
	cin>>a;//if user enters proper input,the loop shouldn't run again
	}
while(!cin);

>> First the program starts.It reaches the 1st do while loop,the one above.

Correct.

>> It enters the loop.It executes cin.clear();

Correct.

>> and empties and throws away everything in the stream in the line while(cin.get()!='\n');.

Correct. IF there is an extra line of garbage from a previous bad input, this will get rid of it. But see below.

>> However since nothing was in the stream at all(it is fresh)the above lines don't do anything.

Incorrect. They will read a line and throw it away no matter what. If you ALREADY had a line of garbage, that's a good thing. If you did not, it will treat the user's VALID input as a line of garbage, read it in, and throw it away. You ALREADY cleared the input stream. If you only want this line to have an effect when there's garbage, you should not clear the stream and instead check cin's error bits, and if they're bad, THEN reset the stream and gobble up the bad line.

>> Then there is cin>>a.The user enters something like '9'.

See above. The last loop already gobbled up the '9' and the '\n' before we ever got here.

>> So a takes the value "9".Since the input was successful,the stream is cleared out and no failure bits are set.

a takes the value 9 if the user enters 9, then the RETURN key, then does the same thing again. See above for why.

>> Then it goes to the while condition.while(!cin);

Correct.

>> The condition is naturally not met as cin was successful.

>> So the do block isn't run again.

Correct.

>> Now things are still fresh and new in the input stream because there is nothing in it.
>> Now there are 2 more such do while block after this,and similar things have to happen thus reading into 3 variables successfully.

Type in 1, 2, 3 , 4 with a line return after each number, then print a, b, and c. The output will be 2, 3, and 4. The 1 has been thrown away.

Consider, instead of using a cin.get() loo[p to clear the cin stream of extra bits, using the ignore function instead. That way anything in the stream is gobbled up, but if there's nothing in the stream, it won't accidentally wait and gobble up and throw out input that you don't want it to.

http://www.cplusplus.com/reference/iostream/istream/ignore/

See this thread also on how to use "ignore".

http://www.daniweb.com/software-development/cpp/threads/90228

Hey VernonDozier.
I am sorry,I still am not completely clear(though its much better now).

I am not able to understand why the user is not asked to enter numbers ,6 times.
It is only 4.
Lets say the first while loop is done with(the loop is terminated,due to a successful read).Now at teh entry of the 2nd loop cin.clear() is run(though there are no failure bits to be erased owing to that successful read before in the 1st loop)
Then comes

while(cin.get()!='\n');

Since the last read was successful,the stream should be automatically cleared out.
So,like you said,it will prompt the user to enter something and immediately clear it out.
Correct?
That means that there has to be 2 prompts for inputs even in the second loop and such is the case in the 3rd loop.
Correct?

I mean,what is the difference between the 1st and 2nd loops?

>> I am not able to understand why the user is not asked to enter numbers ,6 times.
It is only 4.

>> what is the difference between the 1st and 2nd loops?

The difference between the first and the second loops (and it is the same difference between the first and the third loops) is that in the first loop, there is no leftover '\n' in the cin stream, so the first loop that gobbles up all the characters has to gobble up non-whitespace (i.e. the legitimate entries entered by the user). The second and third loops do not.

Suppose you type 8 characters: a 1, 2, 3, and 4, and after each a line return as mentioned in my last example. 8 characters total, 4 lines total. You end up with a = 2, b = 3, c = 4, and the 1 gets thrown away.

int a,b,c;
    do{
    cin.clear();
    while(cin.get()!='\n');//remove failure bits,clear stream if wrong input
    cin>>a;
    }
    while(!cin);//while the entry isn't good
    do{
    cin.clear();
    while(cin.get()!='\n');
    cin>>b;
    }
    while(!cin);
    do{
    cin.clear();
    while(cin.get()!='\n');
    cin>>c;
    }
    while(!cin);

Line 4 grabs the 1 and the first newline.
Line 5 grabs the 2 and LEAVES the second newline in the stream. cin doesn't consume newlines. It STOPS when it sees a newline, but it doesn't consume it.
Line 10 grabs the second newline.
Line 11 grabs the 3 and LEAVES the third newline in the stream. cin doesn't consume newlines. It STOPS when it sees a newline, but it doesn't consume it.
Line 16 grabs the third newline.
Line 17 grabs the 4 and LEAVES the fourth newline in the stream. cin doesn't consume newlines. It STOPS when it sees a newline, but it doesn't consume it.

So altogether cin has grabbed 7 characters. 3 of them have been data and are stored in your three variables, three were newlines and thrown away, and 1 of them was data that was accidentally thrown away. The final newline is still left in the stream unread.

Replace lines 4, 10, and 16 with the command suggested in the post I posted, slightly modified...

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

and see if that helps things. The ignore command will get rid of any stray characters that are in there and it won't do anything if there are no stray characters, which is what you want.

commented: wow thanks! +2

cin doesn't consume newlines. It STOPS when it sees a newline, but it doesn't consume it.

This isn't what I meant. I meant that the >> operator doesn't consume newlines (or any other white space). That's actually not entirely true. It will consume LEADING whitespace, but not TRAILING whitespace(white space is newlines, carriage returns, spaces, tabs, line feeds).

So if a line was the following(note that \t represents a tab and \n a newline)..

\t\t\t567\t\t\n

and this line was in the stream, then this code...

int a;
cin >> a;

will gobble up and throw away "\t\t\t", which is the LEADING white space, then see 567, read that into a, then see a tab and stop. You're left with a containing 567 and the stream containing "\t\t\n".

cin.get()

on the other hand, will read any character it finds, including white space. Whenever you mix the >> operator with the "get" or "getline", you need to be careful and aware of the fact that they behave differently. See the thread I linked for more explanation.

Thanks, VernonDozier.I understood.

And

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

didn't work ,when replaced with the lines you mentioned.

You're right. My memory of what the "ignore" function does was completely incorrect and I passed it along without testing it. My bad. This one's tested. It looks at the error flags and trys to recover only if they're bad. It still has a few problems in that:

1a2
3
4

will lead to 1, 3, 4. "1a2" isn't rejected, only the "a2" part is. You'll need a re-design to catch stuff like that.

I replaced "!cin" with "!cin.good()", though it may not make a difference in the world. Just a force of habit.

#include <iostream>
using namespace std;


int main()
{
    int a,b,c;
    do{
    if(!cin.good())
    {
        cin.clear();
        cin.ignore(80, '\n');
    }
    cin>>a;
    }
    while(!cin.good());
    do{
    if(!cin.good())
    {
        cin.clear();
        cin.ignore(80, '\n');
    }
    cin>>b;
    }
    while(!cin.good());
    do{
    if(!cin.good())
    {
        cin.clear();
        cin.ignore(80, '\n');
    }
    cin>>c;
    }
    while(!cin.good());
    
    cout << a << b << c << endl;
    return 0;
}

The ignore command will get rid of any stray characters that are in there and it won't do anything if there are no stray characters, which is what you want.

That's not quite correct. The ignore function will still block for input if the stream is empty. With one edge case exception, these two snippets are equivalent:

cin.ignore(80, '\n');
{
    char ch;

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

The edge case exception is that ignore() is limited by a count, which could potentially fail to read everything from the stream even if you use the upper limit of std::streamsize (the type used by that count) due to there being more characters in the source than the stream buffer can hold. The loop has no such limitation and will read from the stream until a newline is detected or some kind of failure occurs.

You can get pretty close to a true non-blocking flush using the lessons from my stream flushing thread. Here's some draft code from the I/O chapter of a book I'm working on:

#include <istream>

namespace iosx {
    /// @brief Determines if the next extraction will block.
    ///
    /// @param in The input stream being tested.
    /// @return True if the next extraction will block, false otherwise.
    ///
    /// @remarks The stream is assumed to be interactive and line buffered.
    ///
    template <typename CharT, typename Traits>
    bool is_blocking(std::basic_istream<CharT, Traits>& in)
    {
        typename Traits::int_type nl = Traits::to_int_type(in.widen('\n'));
        typename Traits::int_type last = in.rdbuf()->sungetc();

        if (Traits::eq_int_type(last, Traits::eof())) {
            // Assume that no recently read character will block
            return true;
        }

        // Remove the character that was put back
        in.rdbuf()->sbumpc();

        // Assume a newline (line buffered terminal character) will block
        return Traits::eq_int_type(last, nl);
    }

    /// @brief Extracts remaining characters from an input stream
    ///
    /// @param in The input stream to be flushed.
    /// @return The stream state of in prior to clearing it.
    ///
    /// @remarks The stream is assumed to be interactive and line buffered.
    ///          Calling this function will not cause the stream to block.
    ///          The stream state will always be cleared.
    ///
    template <typename CharT, typename Traits>
    std::ios_base::iostate flush(std::basic_istream<CharT, Traits>& in)
    {
        std::ios_base::iostate state = in.rdstate();
        bool is_fail = in.fail();
        bool is_eof = in.eof();

        in.clear();

        if (!is_eof && (is_fail || !is_blocking(in))) {
            typename Traits::char_type nl = in.widen('\n');
            typename Traits::char_type ch;

            // Use a loop rather than in.ignore() to account for
            // characters in the stream that have not been buffered
            while (in.get(ch) && !Traits::eq(ch, nl))
                ;
        }

        return state;
    }
}

And it would be used something like this:

#include <iostream>
#include "iosx.h" // Assuming this is where you put the above code

bool get_int(int& value, const char *prompt)
{
    do {
        if (std::cin.bad())
            break;

        iosx::flush(std::cin);

        if (prompt != 0)
            std::cout << prompt;

        std::cin >> value;
    } while (!std::cin);

    return !std::cin.bad();
}

int main()
{
    int value;

    if (get_int(value, "Please enter an integer: "))
        std::cout << value << '\n';
}

Though it's there's less work involved in simply flushing when there's a conversion error rather than in all cases:

bool get_int(int& value, const char *prompt)
{
    while (true) {
        if (prompt != 0)
            std::cout << prompt;

        std::cin >> value;

        if (std::cin.good())
            return true;
        else if (std::cin.bad())
            return false;
        else {
            bool is_eof = std::cin.eof();

            std::cin.clear();

            if (!is_eof) {
                char ch;

                while (std::cin.get(ch) && ch != '\n')
                    ;
            }
        }
    }
}

To which you might ask: "Why even bother with a non-blocking flush if it's that simple?" And the answer is that the non-blocking flush (and more importantly the non-blocking test) has more general application than just in an input loop. ;)

@Narue,
I tried this find what 0 meant as a character:

char x=0;
cout<<x;

It turned out be a space.

While clearing out the stream like you mentioned,

{
    char ch;

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

If there was something like"hello hello" in the stream,won't the clearing process be stopped when the space(corresponding to 0) in between is reached?(because while(cin.get(ch)) will be false)

It turned out be a space.

You mean your shell interpreted it as a space. The null character is not a space, it's NUL.

won't the clearing process be stopped when the space(corresponding to 0) in between is reached?

The value of ' ' is not 0. In fact, I challenge you to input a character with the value of 0 using cin. It's not as simple as you might think.

I challenge you to input a character with the value of 0 using cin. It's not as simple as you might think.

Assuming I have a char variable declared, I can do this in one statement.

A char that has an integer equivalent of 0 is an undefined character on output isn't it?

A char that has an integer equivalent of 0 is an undefined character on output isn't it?

I don't know. When I output it as a single char, I get a space. However,
when I use it to mark the end of a string (0 == '\0'), nothing is printed.

Well the ASCII character code says that 0 = NULL so I would think that you cant exactly enter a NULL character. this is a reference that I use from time to time.

A char that has an integer equivalent of 0 is an undefined character on output isn't it?

That's outside the realm of what the C++ standard can dictate. Take it up with your terminal shell. ;)

However, when I use it to mark the end of a string (0 == '\0'), nothing is printed.

Because in that case the character acts as a sentinel.

I would think that you cant exactly enter a NULL character.

Oh, I see. Well, I never said I can enter a NULL character using the keyboard.
Neither did Narue say that this was the challenge. Wait, I'll PM you the answer.

The value of ' ' is not 0. In fact, I challenge you to input a character with the value of 0 using cin. It's not as simple as you might think.

I believe this means she is asking you to input a null into the input stream.

I believe this means she is asking you to input a null into the input stream.

Exactly! But she doesn't say that this must be done using the keyboard.

But she doesn't say that this must be done using the keyboard.

The implication was for interactive user input, since we were talking about a loop to "flush" standard input, and that's typically only meaningful when it comes to user input from the keyboard. However, the challenge was more of a dismissal of the nonexistent problem rather than an actual challenge that needs to be answered.

However, the challenge was more of a dismissal of the nonexistent problem rather than an actual challenge that needs to be answered.

Well, then I guess it doesn't make sense to keep it a secret any more...

#include <iostream>

int main()
{
    char ch;

    // one semicolon == one statement :P :D

    std::cin.rdbuf()->sputbackc('\0'),
    std::cin.get(ch);

    std::cout << "'" << ch << "' ("
        << (int)ch << ")" << std::endl;
}

that's typically only meaningful when it comes to user input from the keyboard

Then, comment out line 9 above and hit CTRL-Z (CTRL-D in unixes) and ENTER.

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.