Loops with cin as conditional

Hello, I am learning about loops and am confused about how cin works when it is the conditional. I have read that cin evaluates to true if the stream is open and in a "good" state, and false otherwise. What I don't quite understand is how the inputs effect the condition. I have this code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  int main()
{
	cout << "Enter a pair of ints or '|' to terminate the program\n";
	int x;
	int y;
	while (cin >> x >> y) {

		if (x == '|' || y == '|') {
			break;
		}
		else {
			cout << x << ", " << y << '\n';
		}

	}
	return 0;
	
}


When the program is run the prompt is printed to console and then it waits for input. Once two integers have been entered it prints out the numbers and then waits for input again. That makes sense since the stream is still in a "good" state, but how exactly does it know that it needs exactly two integers to rerun the loop? Shouldn't entering the two numbers break the loop? Or does the stream just always stay "true" until given "bad" input? My original theory was that cin >> x >> y is really two separate statements that could be restated as:

1
2
while(cin.good()) {
    cin >> x >> y;


However, when this second case is tested it changed the behavior of the program when '|' is entered in console. Instead of immediately ending the program like in the first case, this time it prints out a 0, and either some random number or repeats the second number from the previously entered pair. I assume that the random number is there because the second input is undefined or it repeats because that's the number that is still in the stream. But if that's the case, why does the stream not immediately close and the program cease when the '|' is entered? Isn't '|' supposed to immediately break the loop? Why does the code in the else block still get executed?

Sorry for the long question and thank you for your time.

Kyochi
'|' is not seen as an integer as far as user input goes. So when you enter an '|' it will cause cin to be put in a failure state.

1
2
3
4
while (cin >> x >> y)
{

}
is equivalent to:
while ((cin >> x) >> y)
The >> operator returns the state of the stream after the extraction. So when cin >> x happens, if it is successful, cin will be a good state. cin >> x returns cin itself to allow for operator chaining. So then cin >> y happens, and the final state of the stream is then converted into a boolean to be used with the while loop.

The problem with
1
2
while(cin.good()) {
    cin >> x >> y;

Is that you aren't doing failure checking after the cin >> x >> y operations.
while (cin >> x >> y) returns the state of the stream after attempting to process x and y.

In other words,
while (cin >> x >> y) { } is saying "while we are successfully able to extract two integers from the stream and put them into the x and y variables".

If you wan the user to be able to enter both an integer or a non-numeric character like '|', you need to parse the input as a string first, and then convert it to an integer.

By the way, when posting code, please also post the "#include" part of your code and anything else above main. This will let your program compile without us having to manually add to it.

Last edited on
This is one method to be able to process both numbers and non-numbers:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include <iostream>
#include <string>
#include <stdexcept>

int main()
{
	using namespace std;
    
	cout << "Enter an integer or '|' to terminate\n";
	string str;

	while (cin >> str) {

		if (str == "|")
		{
			break;
		}
		else
		{
			try
			{
				int x = std::stoi(str);
				cout << "You entered: " << x << '\n';
			}
			catch (const std::invalid_argument& ia) {
				cerr << "Invalid input.\n";
				// break; // What should happen here? You decide!
			}

		}
	}
	cout << "Terminating...\n";
	return 0;	
}


std::stoi required C++11 (which is, as you might guess, 8 years old at this point).
It converts a string to an integer, and throws an exception if not possible.
If you don't have C++11 support (you really should, try to enable the -std=c++11 option on your compiler) then you can use this method: https://www.geeksforgeeks.org/converting-strings-numbers-cc/
Last edited on
Hi, Kyochi,

as Genado just said, a >> operation with cin returns always cin itself (same for cout and <<).
But a while(...) needs to converting its expression in its header to a boolean value (true or false).

So how this happens, when the >> operation of cin returns the cin-object itself?
This happened, because cin (and cout) objects have implemented the operator bool() method.
This ensures, that the while()-loop gets its boolean value.

If you want, you could throw a look at this example implementation. I have also the operator!() implemented, for sake of completeness.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>

class S
{
private:
    std::string m_state;
public:
    void state( const std::string& s ) { m_state = s; }
    operator bool ()   { return m_state == "true"  ? true : false; }
    bool operator ! () { return m_state == "false" ? true : false; }
};

int main()
{
    S s;  // s.m_state is empty
    std::cout << ( s ? "true " : "false ") << '\n';
    std::cout << (!s ? "true " : "false ") << '\n'<< std::endl;
    
    s.state("true");
    std::cout << ( s ? "true " : "false ") << '\n';
    std::cout << (!s ? "true " : "false ") << '\n' << std::endl;
    
    s.state("false");
    std::cout << ( s? "true " : "false ") << '\n';
    std::cout << (!s? "true " : "false ") << '\n' << std::endl;
}

Output:
false 
false 

true 
false 

false 
true 
Last edited on
Thanks a lot Ganado and nuderobmonkey!

One more question:
Why is it that when a floating point number gets input as the second variable the loop still runs through with the float having been truncated to an int. It then doesn't loop again. But if a float is input as the first variable or a char is input as either, the loop doesn't get executed at all and the program immediately terminates.

If I understood the above explanations correctly, shouldn't any input that isn't an int invalidate the while loop?

And I will include the #includes next time!
It seems in this case, that cin handles the dot as an end of the second input and reads still up to this dot.
At the second looping, cin reads the dot and returns false, so the while header quits. But I'm not sure.

I have your code a little bit changed, so the states of cin will get showed:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;

int main()
{

	int x;
	int y;
	do {
	    cin >> x >> y;

            if (cin.good() ) cout << "good\n";
            if (cin.fail() ) cout << "fail\n";
            if (cin.bad()  ) cout << "bad\n";
        
	    cout << x << ", " << y << '\n';
		
	} while( cin );
	
	return 0;
	
}
Last edited on
Thanks nuderobmonkey, that makes sense. You guys have been a huge help, I appreciate it.
Topic archived. No new replies allowed.