I am having a problem with an exercise that asks me to receive two integers and print them. But, the program ends when the user enters with the entry '|'
. However, I am testing this and the program enters in an infinite loop.
What is the problem?
#include <iostream>
using namespace std;
int main ()
{
int i1 = 0, i2 = 0;
cin >> i1;
cin >> i2;
while (i1 != int('|') && i2 != int('|'))
{
cout << i1 << endl;
cout << i2 << endl;
cin >> i1 >> i2;
}
return 0;
}
When you std::cin
the non-integer type (charector '|
') inside the loop, it fails. Use std::cin.fail()
check that.
For example, run the following, and you will get the idea why this happened:
while (i1 != int('|') && i2 != int('|'))
{
std::cout << i1 << endl;
std::cout << i2 << endl;
std::cin >> i1 ; // std::cin fails here, in the the case of '|'
if(std::cin.fail()) { std::cout << "Failed"; break;}
std::cin >> i2; // std::cin fails here, in the the case of '|'
if(std::cin.fail()) { std::cout << "Failed"; break;}
}
Above will fix the code. However, you can also write a code for any case of std::cin
failure, by checking with std::cin::fail()
.
while ( std::cin >> i1 && !std::cin.fail() // check wether i1 failed, if not continue
&& std::cin >> i2 && !std::cin.fail() ) // check wether i2 failed, if not continue
{
std::cout << i1 << "\n" << i2 << std::endl;
}
Update: As @AJNeufeld pointed out while (i1 != int('|') && i2 != int('|'))
will fail to read 124
, even the inputs are integers(which is equal to the ASCII code of the vertical pipe character).
A possible solution is to read both values as strings, check for the ‘|
‘ character, if not present, convert the strings to ints, or report errors or break the loop. (Credits to @AJNeufeld)
When you use >>
to extract a value from an istream
, the original stream is returned from the expression. This mean you can replace this code ...
std::cin >> i1;
std::cin >> i2;
with this code:
std::cin >> i1 >> i2;
The result of that expression is again the original istream
, and when used in a boolean context, returns false
if the stream is in a “fail” state. Thus, we can read the two integers and test if that was successful in one simple construct:
if( std::cin >> i1 >> i2 ) {
std::cout << i1 << "\n" << i2 << "\n";
} else {
The above stream will enter a fail state, when it is trying to read an integer and encounters a non-integer character, such as the vertical pipe. To test for this, we need to first clear the error state, then see what character was in the stream that caused the integer read to fail. We can do this by peeking at what the next character is.
} else {
std::cin.clear(); // reset the fail state
if (std::cin.peek() == '|') {
std::cout << "Found end of input marker (|)\n";
} else {
std::cout << "Invalid input!";
}
After determining whether it was the vertical pipe or not, it is wise to clear out all characters in the stream up to the end of the input line.
// skip all characters in the stream up to the end of the current line.
std::cin.ignore(std::numeric_limits<streamsize>::max(), '\n');
}
Put the above code in a loop, add a break
statement when the vertical pipe is found, and you will be looping, reading integer values in pairs, until you type in the |
.
while ( !std::cin.eof() ) {
if( std::cin >> i1 >> i2 ) {
std::cout << i1 << "\n" << i2 << "\n";
} else {
std::cin.clear(); // reset the fail state
if (std::cin.peek() == '|') {
std::cout << "Found end of input marker (|)\n";
break;
} else {
std::cout << "Invalid input!";
}
// skip all characters in the stream up to the end of the current line.
std::cin.ignore(std::numeric_limits<streamsize>::max(), '\n');
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With