From Stroustrup's TC++PL, 3rd Edition, Section 21.3.3:
If we try to read into a variable v and the operation fails, the value of v should be unchanged (it is unchanged if v is one of the types handled by istream or ostream member functions).
The following example appears to contradict the above quote. Based on the above quote, I was expecting the value of v to remain unchanged -- but it gets zeroed. What's the explanation for this apparent contradictory behaviour?
#include <iostream>
#include <sstream>
int main( )
{
std::stringstream ss;
ss << "The quick brown fox.";
int v = 123;
std::cout << "Before: " << v << "\n";
if( ss >> v )
{
std::cout << "Strange -- was successful at reading a word into an int!\n";
}
std::cout << "After: " << v << "\n";
if( ss.rdstate() & std::stringstream::eofbit ) std::cout << "state: eofbit\n";
if( ss.rdstate() & std::stringstream::failbit ) std::cout << "state: failbit\n";
if( ss.rdstate() & std::stringstream::badbit ) std::cout << "state: badbit\n";
return 1;
}
The output I get using x86_64-w64-mingw32-g++.exe (rubenvb-4.7.2-release) 4.7.2 is:
Before: 123
After: 0
state: failbit
Thanks.
From this reference:
If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set (until C++11)
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. (since C++11)
It seems that your compiler is compiling in C++11 mode, which changes the behavior.
The input operator uses the locale facet std::num_get whose get function invokes do_get. For C++11 it's specified to use std::strtoll et. al. type of functions. Before C++11 it apparently used std::scanf style parsing (going by the reference, I don't have access to the C++03 specification) to extract the numbers. The change in behavior is due to this change in parsing the input.
The operator >> is a formatted input operator.
As such is dependent on the locale for how input is read from the stream:
[istream.formatted.arithmetic]
As in the case of the inserters, these extractors depend on the locale’s num_get<> (22.4.2.1) object to perform parsing the input stream data. These extractors behave as formatted input functions (as described in 27.7.2.2.1). After a sentry object is constructed, the conversion occurs as if performed by the following code fragment:
typedef num_get< charT,istreambuf_iterator<charT,traits> > numget;
iostate err = iostate::goodbit;
use_facet< numget >(loc).get(*this, 0, *this, err, val);
setstate(err);
As we can see above the value is actually set by the numget facet of the locale imbuded onto the stream.
num_get virtual functions [facet.num.get.virtuals]
Stage 3:
The numeric value to be stored can be one of:
zero, if the conversion function fails to convert the entire field. ios_base::failbit is assigned to err.
the most positive representable value, if the field represents a value too large positive to be represented in val. ios_base::failbit is assigned to err.
the most negative representable value or zero for an unsigned integer type, if the field repre- sents a value too large negative to be represented in val. ios_base::failbit is assigned to err.
The definition of stage 3 changed drastically between n2723 -> n2798
Where do I find the current C or C++ standard documents?
num_get virtual functions [facet.num.get.virtuals]
Stage 3: The result of stage 2 processing can be one of:
A sequence of chars has been accumulated in stage 2 that is converted (according to the rules of scanf) to a value of the type of val . This value is stored in val and ios_base::goodbit is stored in err .
The sequence of chars accumulated in stage 2 would have caused scanf to report an input failure. ios_base::failbit is assigned to err.
Related
Being following the book "Programming Principles and Practice Using C++" by Bjarne Stroustrup for learning C++ right from the very basics. It all proved good until this happened...
int main()
{
cout << "Please enter your first name and age\n";
string first_name = "???"; // string variable
int age = -1; // integer variable
cin >> first_name >> age; // read a string and then integer
cout << "Hello, " << first_name << " (age " << age << ")\n";
}
Now, as the above code (under the section Input and Types, Chapter 2) suggests, it outputs a string which familiarizes us to the name and age of a person. As I have initialized the integer variable age to -1, the program must return -1 to the monitor if I, in case by mistake, input a string value into age. The issue is that it just won't happen in my computer. I have tried and compiled and run the program 19 times (I do remember it...) but the result is always the same: it outputs 0 instead of -1.
For e.g. if I enter ABCXYZ 16, then the output will be a nice and simple Hello, ABCXYZ (age 16). But if the input was 16 ABCXYZ, then the output comes out to be Hello, ABCXYZ (age 0), which I expected to be Hello, ABCXYZ (age -1) as the string ABCXYZ won't be read into age (it is an integer variable) and thus give out the initialized value because it wasn't overwritten.
Any idea?
P.S.: I'm using Code:Blocks with GCC - 8.1.0
std::istream& operator>>(int &value) calls std::num_get::get() internally. From cppreference std::num_get::get() the behavior changed in c++11.
Having v to denote the variable we read into, until c++11 we had:
If an error occurs, v is left unchanged.
However since c++11:
If the conversion function fails to convert the entire field, the
value 0 is stored in v
If the conversion function results in a
positive or negative value too large to fit in the type of v which is
a signed integer type, the most positive or negative representable
value is stored in v, respectively
If the conversion function results
in a value not to fit in the type of v which is an unsigned integer
type, the most positive representable value is stored in v.
You are compiling using a compiler and C++ standard library configured to be compatible with a standard after c++11, so when std::cin fails to read the field, the value of 0 is stored into age.
The issue is isolated to the >> operator, where it fails to convert your string input into an integer (which is expected, as std::cin >> x handles expected input, from the type you define for x), and hence returns a 0, irrespective of whatever value you initialized the integer variable with.
This was done since C++ 11 as Kamil mentioned, and conforming to previous standards, the value would have been left unchanged and would return a -1 for your case.
You can check if cin fails or passes for the same to draw a conclusion yourself:
int main()
{
int age = -1;
std::cin >> age;
if(cin)
std::cout << age;
}
If you enter an integer (as expected from the type of age) you'd get the output for the value of age you initialized it to, else if you enter a string, cin will fail (and its failbit will be triggered, resulting in false) and nothing will be displayed, in accordance with the if-statement above.
int a, b;
cin >> a >> b;
cout << a << endl << b;
input1: 3.5 5.5
input2: 3 5.5
check this code
The behaviour of your code is undefined up to and including C++03. The stream halts on the .. From C++11 onwards b is set to 0; prior to that it was not modified. Currently you read its value in the fail case, which is careless.
A good fix is to always write something like
if (cin >> a >> b){
// yes, all good
} else {
// a parsing error occurred
}
On the true branch, values are guaranteed to have been written to a and b.
It reads:
spaces/tabs/newlines (just consumes that if any)
digits till something different (the dot in your case) and parse them as the number
So a becomes 3.
Then, when it tries to read the second number it is still at the . , but a 'dot' is different from spaces and digits, so it does not consume any char and assignes 0 to b and set the failbit
Thanks to #tobi303 for the specs link:
(until C++11) If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set.
(since C++11) If extraction fails, zero is written to value and failbit is set.
The input is not a decimal value; it's a text string, and the code will translate that text string into an integer value. So, what's the integer value that the string "3.5" represents? It's 3, just as if the input had been "3 5": the code that translates the text reads as much of the text as makes sense, then stops. What happens after that depends on what caused the translation to stop. If it hit a whitespace character, all is well. If it hit something else (in this case, a .), you're in trouble.
From Stroustrup's TC++PL, 3rd Edition, Section 21.3.3:
If we try to read into a variable v and the operation fails, the value of v should be unchanged (it is unchanged if v is one of the types handled by istream or ostream member functions).
The following example appears to contradict the above quote. Based on the above quote, I was expecting the value of v to remain unchanged -- but it gets zeroed. What's the explanation for this apparent contradictory behaviour?
#include <iostream>
#include <sstream>
int main( )
{
std::stringstream ss;
ss << "The quick brown fox.";
int v = 123;
std::cout << "Before: " << v << "\n";
if( ss >> v )
{
std::cout << "Strange -- was successful at reading a word into an int!\n";
}
std::cout << "After: " << v << "\n";
if( ss.rdstate() & std::stringstream::eofbit ) std::cout << "state: eofbit\n";
if( ss.rdstate() & std::stringstream::failbit ) std::cout << "state: failbit\n";
if( ss.rdstate() & std::stringstream::badbit ) std::cout << "state: badbit\n";
return 1;
}
The output I get using x86_64-w64-mingw32-g++.exe (rubenvb-4.7.2-release) 4.7.2 is:
Before: 123
After: 0
state: failbit
Thanks.
From this reference:
If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set (until C++11)
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. (since C++11)
It seems that your compiler is compiling in C++11 mode, which changes the behavior.
The input operator uses the locale facet std::num_get whose get function invokes do_get. For C++11 it's specified to use std::strtoll et. al. type of functions. Before C++11 it apparently used std::scanf style parsing (going by the reference, I don't have access to the C++03 specification) to extract the numbers. The change in behavior is due to this change in parsing the input.
The operator >> is a formatted input operator.
As such is dependent on the locale for how input is read from the stream:
[istream.formatted.arithmetic]
As in the case of the inserters, these extractors depend on the locale’s num_get<> (22.4.2.1) object to perform parsing the input stream data. These extractors behave as formatted input functions (as described in 27.7.2.2.1). After a sentry object is constructed, the conversion occurs as if performed by the following code fragment:
typedef num_get< charT,istreambuf_iterator<charT,traits> > numget;
iostate err = iostate::goodbit;
use_facet< numget >(loc).get(*this, 0, *this, err, val);
setstate(err);
As we can see above the value is actually set by the numget facet of the locale imbuded onto the stream.
num_get virtual functions [facet.num.get.virtuals]
Stage 3:
The numeric value to be stored can be one of:
zero, if the conversion function fails to convert the entire field. ios_base::failbit is assigned to err.
the most positive representable value, if the field represents a value too large positive to be represented in val. ios_base::failbit is assigned to err.
the most negative representable value or zero for an unsigned integer type, if the field repre- sents a value too large negative to be represented in val. ios_base::failbit is assigned to err.
The definition of stage 3 changed drastically between n2723 -> n2798
Where do I find the current C or C++ standard documents?
num_get virtual functions [facet.num.get.virtuals]
Stage 3: The result of stage 2 processing can be one of:
A sequence of chars has been accumulated in stage 2 that is converted (according to the rules of scanf) to a value of the type of val . This value is stored in val and ios_base::goodbit is stored in err .
The sequence of chars accumulated in stage 2 would have caused scanf to report an input failure. ios_base::failbit is assigned to err.
I have a problem about cin.
int main(void)
{
int a;
float b;
cin >> a >> b;
}
When I give a floating number (such as 3.14) as input, neither a nor b get the complete value (3.14): the output is a=3, b=0.14.
I know that cin will split the input by space, tab or Return, but 'dot' will not, right?
And why will the following code work?
int main(void)
{
int i=0;
int k=0;
float j=0;
cin >> i >> k >> j; // i =3, j=k=0
}
And one more problem, what benefit will compiler do this for us?
Thanks!
You've declared a to be of type int, in which case what do you expect it to do with the "."?
failbit The input obtained could not be interpreted as an element of
the appropriate type. Notice that some eofbit cases will also set
failbit.
The other mention you have works fine what is the issue you are asking about? You've cined 3 variables what did you expect here? 0 is valid for float or int.
cin >> a >> b;
Given an input of 3.14, the first parse on the dot (period) because dot doesn't fit the syntax for an integer. The second parse picks up with .14, which parses just fine.
cin >> i >> k >> j;
This is problematic with an input of 3.14. The first parse once again stops on the dot. The second parse can't restart with the dot, so it marks the input stream as failed.
Always check status when doing I/O.
The formatted input functions work quite simple:
They skip leading whitespace if any.
They try to read a format matching the type given.
If reading the value fails because the data doesn't match the required format, they set std::ios_base::failbit. If reading fails the input shouldn't change the variable attempted to be read (the standard input operators follow this rule but user defined input operator might not).
The first value you try to read is an int. Reading an int means that a optional leading sign is read followed by a sequence of digits (where, depending on your settings and the value given, the stream may read octal or hexadecimal numbers rather than decimal ones). That is, the int receives the value 3 and reading stops right in front of the ..
Depending on what you read next, the next read fails or doesn't:
In the first code you try to read a floating point value which starts with an optional sign, followed by an optional integral parts, followed by an optional thousands separator, followed by an optional fractional part, followed by an optional exponent. At least one digit is required in either the integral or the fractional part. In your example, there is only a thousands separate followed by a fractional part.
When trying to read an integer, a . is found which isn't a valid part of an int and reading fails.
After attempting to read a value, you should always try if the read operation was successful and report potential errors:
if (in >> value) {
std::cout << "successfully read '" << value << "'\n";
}
else {
std::cerr << "failed to read a value from input\n";
}
Note, that after a failed read you may need to clean up as well, e.g., using
in.clear();
in.ignore();
This first clears the error flags (without this, the stream would ignore any further attempts to read the data) and then it ignores the next character.
cin is reading input "3.14" and you ask to put it into an integer and then a float.
So cin starts reading, finds "3", then finds "." which is not integer. Stores 3 into a and continues. ".14" is valid float and it puts it into b.
Then you ask to read int, int, float. The second integer is not matched and cin stops, but it only appears to be working. Actually, it failed.
The compiler can't warn you that you're doing something which will not work, because the input is not known at compile time.
#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;
}
How does this code know when to finish grabbing input values and display sum? Why does it only end when I input a non-integer value?
Your loop ends when std::istream& operator>>(int) evaluates to false. That happens if the stream has hit end of file or has been marked as in error. Entering a floating point number causes the latter to occur.
Details:
Every stream includes a bitmask that indicates the status of the stream. The bits in the mask comprise an eof bit, a fail bit, and a bad bit (std::ios_base::eofbit, std::ios_base::failbit, and std::ios_base::badbit). The first is rather obvious: It's set upon hitting EOF. The next two are a bit trickier. std::ios_base::failbit is set when an input operation failed to read the expected characters, or when an output operation failed to generate the desired characters. std::ios_base::badbit is set when something goes very wrong, e.g., your disk is fried. The conversion from a stream reference to a boolean eventually involves checking that none of these bits is set. The decimal point in a floating point number causes the fail bit to be set, and that in turn causes your loop to end.
Because as long as you are typing intergers, the cin >> value expression evaluates to true. If you type a non-integer, the expression will fail because you would be trying to put a non-integer into your value variable of type int.
while (std::cin >> value) will ends when there is no input (ctrl-D or end of stream) or has something bad occurred. Your input of a non-integer gives an error then it terminate the while
The line while (std::cin >> value) is saying to continue running while std::cin >> value is true. Conveniently, since value is an int, if you enter value which can't be implicitly converted to an int, then that expression will return false. Otherwise, it keeps going.