Effects on Input Variable after Failed Input Stream - c++

I was working on the following code.
#include <iostream>
int main()
{
std::cout << "Enter numbers separated by whitespace (use -1 to quit): ";
int i = 0;
while (i != -1) {
std::cin >> i;
std::cout << "You entered " << i << '\n';
}
}
I know that using while (std::cin >> i) would have been better but I don't understand a specific occurrence.
If I provide an invalid input, the loop becomes infinite because the Input Stream enters a failbit state. My question is that what happens to the input variable i? In my case, it becomes 0 regardless of the previous value entered. Why does it change to 0 after an invalid input? Is this a predefined behaviour?

You get zero because you have a pre-C++11 compiler. Leaving the input value unchanged on failure is new in the latest standard. The old standard required the following:
If extraction fails, zero is written to value and failbit is set. If
extraction results in the value too large or too small to fit in
value, std::numeric_limits::max() or std::numeric_limits::min()
is written and failbit flag is set.
(source)
For gcc, you need to pass -std=c++11 to the compiler to use the new behavior.

Related

How to read unknown number of inputs?

I am learning C++ using the book C++ Primer.
In Section 1.4.3, the following example code about reading the unknown number of inputs is given.
#include <iostream>
int main()
{
int sum = 0, value = 0;
// read until end-of-file, calculating a running total of all values read
while (std::cin >> value)
sum += value; // equivalent to sum = sum + value
std::cout << "Sum is: " << sum << std::endl;
return 0;
}
According to the book, if we give an input of 3 4 5 6, the output will be Sum is: 18
But when I try this on my computer(Windows 10 with MinGW), The code does not end. It just keeps on asking for input even if I enter a newline. It works only when I enter a non-int input like f.
Is this expected? If yes, is there any code that stops after inputting a newline?
I am quite new to c++ and I have already learned python, so getting stuck so early on is quite frustrating.
Thanks and regards.
You need to terminate your input by an End-Of-File-character (i.e. CTRL-Z on Windows, CTRL-D on Mac/Unix), not just by an End-Of-Line (i.e. Enter).
A simple Enter is interpreted as white space, which will be simply ignored by operator>> when reading into an integral data type.
CTRL-Z / End-Of-File, in contrast, makes any operator>> fail with an error.
See also this SO answer.
Note: Entering f will also terminate your loop, since f is not considered a valid integral number; Hence, std::cin >> value with value being of type int and an input like f will fail as well. To be more accurate: operator>> actually returns a reference to the input stream, but if reading in a value fails, failbit is set on the stream, and then interpreting the stream object in a boolean expression (implicitly calling basic_istream::operator bool()) returns false; So maybe the author of the book did not want to explain these details at the respective section in the book :-)
Is this expected?
Yes, as operator>> ignores leading whitespace by default, which includes line breaks.
If yes, is there any code that stops after inputting a newline?
Use std::cin.getline() or std::getline() instead of operator>>. You can then use operator>> with a std::istringstream to parse values from each line, eg:
#include <iostream>
#include <string>
#include <sstream>
int main()
{
std::string line;
int sum, value;
do
{
std::cout << "Enter a set of numbers, or a blank line to exit: ";
if (!std::getline(std::cin, line) || line.empty())
break;
// read until end-of-line, calculating a running total of all values read
std::istringstream iss(line);
sum = 0;
while (iss >> value)
sum += value; // equivalent to sum = sum + value
std::cout << "Sum is: " << sum << std::endl;
}
while (true);
return 0;
}
Live Demo
Is this expected?
Yes, Thats what while (std::cin >> value) does. See this answer for more explanations: How is "std::cin>>value" evaluated in a while loop?
is there any code that stops after inputting a newline?
No, as >> simply ignore a white space(also #StephanLechner mentioned it)
What you can do instead is:
Just give a condition; if it satisfies just break the loop. you
can also provide a console out to make it more understandable to the
user. For example:
std::cout << "Enter value to sum or press -1 to exit" << std::endl;
while (std::cin >> value && value != -1) // if value == -1, loop stops.
{
sum += value;
}
You can simply terminate by the end of character:
CTRL-Z on Windows
CTRL-D on Mac/Unix

Trying to understand cin behavior

I am writing software that takes a (huge) input stream from stdin and reads it into a vector of floats. I want to capture the case that the stream contains characters like commas, and either fail to accept it, or simply ignore everything that cannot be parsed as float (whichever is easier to implement, I have no preference). I have noticed the following behavior: when I call
echo "1.4, -0.7 890 23e-3" | ./cintest
this version
#include <iostream>
using std::endl;
using std::cin;
using std::cout;
int main ( int argc, const char* argv[] ){
float val;
while (cin >> val) {
cout << val << endl;
}
return 0;
}
prints
1.4
while this version
#include <iostream>
using std::endl;
using std::cin;
using std::cout;
int main ( int argc, const char* argv[] ){
float val;
while (cin) {
cin >> val;
cout << val << endl;
}
return 0;
}
prints
1.4
0
Without the comma, the first one prints
1.4
-0.7
890
0.023
while the second one prints
1.4
-0.7
890
0.023
0.023
Could somebody please explain what is going on here?
The first version of your code
while (cin >> val) {
tries to parse a float, and then checks whether the stream state is good. (Specifically, it calls operator>> to do the extraction, which will set failbit on error, and then uses the bool conversion to test failbit).
So, if the stream state is bad (because it couldn't convert , to a float), the loop body is not entered. Hence it terminates on the first failed conversion.
The second version
while (cin) {
cin >> val;
checks if the stream state is good (which just tells you the previous conversion succeeded), then tries parsing a float, and then assumes this succeeded without checking. It ought to check the stream state after conversion before using the float value, which in this case is left over from the previous iteration.
In a correct implementation, when conversion fails, you should check whether fail() is true but eof() is false (ie, the conversion failed for some reason other than end-of-file). In this case, use ignore() to discard input - you could either require whitespace (and ignore until the next space), or just ignore one character and try again.
Note that the ignore documentation linked above includes sample code with correct error handling. If we choose to skip a single character on failed conversions, your code would become:
for(;;) {
float val;
std::cin >> val;
if (std::cin.eof() || std::cin.bad()) {
break;
} else if (std::cin.fail()) {
std::cin.clear(); // unset failbit
std::cin.ignore(1); // skip next char
} else {
std::cout << val << '\n';
}
}
Your results have to do with when the >> fails.
In both versions, you read your values and reach the comma (or EOF). The read obviously fails, because , and EOF are not valid integers that >> can parse. So >>'s return value (the stream itself) converts to false, and you exit the loop in the first version (this is how it should work).
In the second version (which isn't how you should usually do it), however, you are still printing out whatever value ends up in val. In C++ before C++11, val remains the same; since C++11 >> writes 0 on failure.
TL;DR: Your second version stops the loop to late, and writes one pass of garbage.
It's because in the second one you have a bug.
You should always check to see if the formatted input operator>> actually worked.
So this code:
cin >> val;
cout << val << endl;
Should be written as:
if (cin >> val) {
cout << val << endl;
}
If the operator>> fails. Then it will set one of the fail bits on the stream and not put any value into val. So there is no need to print val because nothing was put into it.
This is why your second version prints garbage when it has no data left to read. The read fails and then you print out a value. Then you try and re-start the loop (which fails).
The first one works correctly.
while (cin >> val) {
cout << val << endl;
}
Because you read a value then check to see if the read works before entering the loop.
std::cin is an instantiation of std::istream
when there is a comma or any invalid data type at any point the operator >> fails. hence your code prints the last known value of 'val'.
Linked here is a reference for 'std::istream >>'
http://www.cplusplus.com/reference/istream/istream/operator%3E%3E/

Confusion in cin functionality with int dataype

{
int n;
cin>>n;
cout<< n;
}
The output is 0 when any alphabet or special character is given as input.
In C its not the case when I used scanf(); and printf(). It prints the corresponding ASCII value.
Please explain why is this happening?
Please explain why is this happening?
In the documentation of the std::istream& operator>>(std::istream&, int) it's stated (emphasis mine):
If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set.
For c++11 code it seems initialization is guaranteed:
If extraction fails, zero is written to value and failbit is set. If extraction results in the value too large or too small to fit in value, std::numeric_limits<T>::max() or std::numeric_limits<T>::min() is written and failbit flag is set.
Assumed you run a debug build of your code, n is probably initialized with 0 automatically, but technically accessing it is undefined behavior, since it wasn't initalized in that case you describe.
You have to check cin's state after input to detect if a failure occured during the number extraction, or if you can safely use the now-initialized value:
int n;
std::cin >> n;
if(std::cin) {
std::cout << n << std::endl;
}
else {
std::cin.clear(); // Clear the streams fail state
std::string dummy;
std::cin >> dummy; // Consume the non numeric input
std::cout << "Wrong input, '" << dummy << "' is not a number."
}
In both C and C++, when inputting an integer, the driver input function will read numeric characters until a character that is not a number is read.
For example, the sequence "123GHI" should return the value 123.

Why happens to variable when cin breaks? C++

I have the following code snippet:
int a = 1;
double b = 3.14;
string c = "hi";
cin >> a >> b >> c;
cout << a << " " << b << " " << c << endl;
If I enter apple 11 tammy, why does it cout: 0 3.14 hi instead of: 1 3.14 hi?
Why does the value of a change when cin is broken?
Why does the value of a change when cin is broken?
This is the expected behavior of std::basic_istream::operator>> since C++11; If extraction fails the value will be set to 0.
If extraction fails, zero is written to value and failbit is set. If extraction results in the value too large or too small to fit in value, std::numeric_limits<T>::max() or std::numeric_limits<T>::min() is written and failbit flag is set.
Note that after failbit being set, the following input won't be performed; that means b and c will remain their original values.
BTW: Before C++11 the value will be left unmodified when extraction fails.
If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set.
Try stringstream instead. here is a link explaining the same issue in detail:
http://www.cplusplus.com/doc/tutorial/basic_io/

Why does a program become broken when a character is input when prompted to input an integer value?

Example:
int i=0;
do {
cin >> i;
if(!isdigit(i)) cout << "Error. Must be an integer\n\n";
}
while(cin.fail());
If a character rather than an integer was input by the user, the program would break and go into some infinite loop for some reason. Why is this? Is there no way to prevent it from happening? the isdigit() function doesn't seem to work well with int variables, only with char variables.
You seem to be confused about how input works. When you write
std::cin >> i;
and i is an int, the input stream will extract the text for
an integral value: it will skip whitespace, then extract
a possible sign, then one or more digits. It will then convert
this text into an int, and store it where requested. If it
doesn't find text in the appropriate format, it will set an
error status (failbit), which will remain set until you clear
it. And it will not modify i; you must always check that
input has succeeded before using the variable input.
isdigit, on the other hand, has undefined behavior unless
the integer it is passed is in the range [0,UCHAR_MAX]. (Note
that range. It means that you cannot simply pass it a char.)
It's not clear what you're trying to do here. If it's just
enter an int:
int i;
while ( !(std::cin >> i) ) {
std::cout << "Error: integer wanted" << std::endl;
std::cin.clear(); // Clear error...
std::cin.ignore( INT_MAX, '\n' ); // And ignore characters which caused it
// (up until next '\n')
}
If you want a single digit:
int i = std::cin.get();
while ( i != EOF && !isdigit( i ) ) {
std::cout << "Error, single digit wanted" << std::endl;
i = std::cin.get();
}
char ch = i; // NOW (and only now) can you convert into int.
std::cin.get() returns an int, in order to handle the out of
band value EOF. The int in guaranteed to be in the range
[0...UCHAR_MAX], or to be EOF, so you can pass it directly
to isdigit. Only once you've finished these tests should you
convert it into a char (since a digit is a character).
You always need to check after reading that your input was successful, e.g.
if (std::cin >> i) {
// process input
}
If the input fails std::ios_failbit is set. While this flag is set the stream won't accept any input and convert to false. To clear the error flags you use
std::cin.clear();
Clearing the error flags won't remove the offending character. You'll need to get rid of them, e.g., using
std:: ignore();
The above code certainly doesn't create an infinite loop. But the loop happens usually when a digit is expected and a non-digit is given, so the characters in the buffer will stay there and the stream is in an bad state. This will happen until the stream is appropriately cleared, so that the stdio can continue to read according to the format specification. Of course the loop has to be done iny our program, as stdio is not looping on it's own.
To clear the input and ingore what is left there you can use this:
std::cin.clear();
std::cin.ignore();