The scenario is: input integers and characters alternatively and read them into variables of the right type. I took the straightforward approach: read anyways as if they were all integers; when failed, reset cin flags and read as characters.
int a;
char c;
while (true) {
cin >> a;
if (cin.fail()) {
if (cin.eof()) {
cout << "eof" << endl;
break;
}
cin.clear();
cin >> c;
cout << "fail: " << c << ": " << int(c) << endl;
}
else {
cout << "success: " << a << endl;
}
}
It works just fine except for the very two characters: +
, -
. For instance, when you input 2 4 + 5 *
, the output would be:
success: 2
success: 4
fail: 5: 53
fail: *: 42
eof
For *
, it works; but for +
, it seems that +
is lost and 5
is read instead. I did some tests myself (e.g. using cin.get()
instead) and found that: after cin >> a
failed when encoutering +
, +
is consumed and the stream position points at the space between +
and 5
.
What makes +
and -
special? After some researches, I think the reason is possibly that: when cin
expects an integer, the +
or -
it encounters is accepted as a possible prefix of integers like +5, -3, etc. This leads to the fact that +
is consumed, rather than remains in the input stream like other characters.
How do you interpret the problem? How to fix the code to make it function properly?
PS: I know that one alternative solution is to read them all as strings and then do further parsing. I'm just curious whether it's possible to modify it based on the original approach. This way I could be more clear about the machanisms behind cin
.
I think this post can be closed now. Thanks for all the comments and answers. The opinions and advice you shared are greatly appreciated, which I learned a lot from.
As I've said, it's not about practical use and I'm not looking for a well-rounded solution in the first place. In practice I will surely take the string-based approaches as suggested by you. It's just a small problem I ran into, after which I decided to take a short digression and play around the issue a little bit.
As for the question I raised, i.e. fixing the code, I've learned some from the answers below and official Docs. Using functions like cin.putback() cin.peek() cin.tellg() cin.seekg()
will help tackle the problem.
The comments to your question show that there are much more to think than the mere "+/-" issue.
Yet as to tackle this issue, your analysis is correct in the sense that these characters can be interpreted as the beginning of an int
and got consumed.
A workaround for this issue only is to parse char
by char
and not by int
and to handle specifically +
and -
:
int a;
char c;
while (true) {
char ch;
if (std::cin >> ch) {
if (ch == '+' || ch == '-') {
// Consume the special character and continue
std::cout << "special char: " << ch << '\n';
continue;
} else {
// Try to read the character as an integer
std::cin.putback(ch);
if (std::cin >> a) {
std::cout << "success: " << a << '\n';
} else {
std::cin.clear();
std::cin >> c;
std::cout << "fail: " << c << ": " << int(c) << '\n';
}
}
} else if (std::cin.eof()) {
std::cout << "eof" << '\n';
break;
} else {
std::cin.clear();
std::cin >> c;
std::cout << "fail: " << c << ": " << int(c) << '\n';
}
}
Take notice of the usage of putback
that allows to "unconsume" +
or -
and then try to read an int
.
input:
24+5
output
success: 24
special char: +
success: 5
But remember: it's only a quick workaround for this single issue but parsing a possibly ill -formed expression will raise many other issue that won't be solved by merely elaborating upon this fix.