In Bjarne Stroustrup's Programming Principles and Practice Using C++ (Sixth Printing, November 2012), if (cin) and if (!cin) are introduced on p.148 and used in earnest on p.178. while (cin) is introduced on p.183 and used in earnest on p.201.
However, I feel I don't fully understand how these constructs work, so I'm exploring them.
If I compile and run this:
int main()
{
int i = 0 ;
while (cin) {
cout << "> ";
cin >> i ;
cout << i << '\n';
}
}
I get something like:
$ ./spike_001
> 42
42
> foo
0
$
Why is it that entering "foo" apparently causes i to be set to 0?
Why is it that entering "foo" causes cin to be set to false?
Alternatively, if I run and compile this:
int main()
{
int i = 0 ;
while (true) {
cout << "> ";
cin >> i ;
cout << i << '\n';
}
}
I get something like:
$ ./spike_001
> 42
42
> foo
> 0
> 0
...
The last part of user input here is foo. After that is entered, the line > 0 is printed to stdout repeatedly by the program, until it is stopped with Ctrl+C.
Again, why is it that entering "foo" apparently causes i to be set to 0?
Why is it that the user is not prompted for a new value for i on the next iteration of the while loop after foo was entered?
This is using g++ (Ubuntu/Linaro 4.6.3-1ubuntu5) 4.6.3.
I'm sorry for such a long question, but I think it all boils down to, "How is cin evaluated?"
Well, std::cin (or more precisely std::basic_ios) has an operator bool to implicitly convert the std::cin object to a bool when requested (for example in your if evaluation).
The semantic is as follows:
Checks whether the stream has no errors. Returns true if the stream has no errors and is ready for I/O operations. Specifically, returns !fail().
Why is it that entering "foo" apparently causes i to be set to 0?
Again, why is it that entering "foo" apparently causes i to be set to 0?
Because operator>> on an int expects an integer in the string.
From cppreference:
If extraction fails (e.g. if a letter was entered where a digit is expected), value is left unmodified and failbit is set.
Why is it that entering "foo" causes cin to be set to false?
Because the fail bit is set, therefore leading fail() to return true.
Why is it that the user is not prompted for a new value for i on the next iteration of the while loop after foo was entered?
That is because std::cin has the fail bit set, therefore it fails to get the input and just prints the old value of i which is 0.
When you use the >> operator on a stream, it attempts to extract a value of that type from the string. In other words, when you do cin >> i where i is an int, the stream attempts to pull an int from the stream. If this succeeds, i is set to the extracted value, and all is well. If it fails, the stream's badbit is set. This is important because treating a stream as a bool is equivalent to checking if it's badbit is set (if (cin) is like if (cin.good())).
So anyway... what's happening is that foo is setting the badbit since the extraction fails. Really, you should be checking if the extraction succeeds directly:
if (cin >> i) { /* success */ }
On a code quality note, I suspect you're using using namespace std;. Please be aware that this can be harmful.
Related
I'm currently learning how while (cin >> num) work and I found out that there are two steps.
First one is the operator>> function return a istream object with error state, and the second is bool converter that convert istream object into bool depend on its state.
But I find it confusing that in the bool convert function, it will return 0 only if failbit or badbit is set. And the operator>> function will set eofbit if it read EOF.
bool convert function: https://www.cplusplus.com/reference/ios/ios/operator_bool/
operator>> function: https://www.cplusplus.com/reference/istream/istream/operator%3E%3E/
In this case, After I enter EOF the bool converter should return 1 because the failbit and badbit aren't set.
Therefore, I use the below program to check what actually happened to the error bit after I enter EOF. And I find out that the failbit will be set after entering EOF!!
So I'm wondering if anyone can help me understand why is failbit set?
#include <iostream>
using namespace std;
int main()
{
int num;
cin >> num;
cout << cin.eof() << " " << cin.fail() << " " << cin.bad() << endl;
return 0;
}
Input: ^Z(on windows using qt creator, non qt c++ project)
Output: 1 1 0
Input: ^D(on windows using qt creator, non qt c++ project)
Output: 0 1 0
eofbit is set when a read operation encounters EOF while reading data into the stream's buffer. The data hasn't been processed yet.
failbit is set when the requested data fails to be extracted from the buffer, such as when reading an integer with operator>>. While waiting for digits to arrive, EOF could occur. eofbit alone is not enough to enter an error state, as there may be usable data in the buffer.
So, for example, imagine a while (cin >> num) loop is used and the user enters 123<Ctrl-Z>.
on the 1st iteration, operator>> reads 1, 2, 3 into the buffer, then encounters Ctrl-Z, so it sets eofbit and stops reading. 123 is then extracted from the buffer into num and the operator exits. At this point, the stream is not yet in an error state. When the stream's bool conversion is evaluated by while, it returns true, allowing the while body to be entered so it can process num.
on the next iteration, operator>> sees eofbit is set, preventing further reading. There is nothing left in the buffer to extract into num, so the operator sets failbit and exits. The stream is now in an error state. When the stream's bool conversion is evaluated by while, it returns false, breaking the while loop.
If the EOF is the first input, the operator>> fails to read an integer, so the stream enters the fail() state.
If you type at least one digit before the Ctrl-Z, that digit is read and the input succeeds.
I am new to c++ and was making a program in c++11 that sorts a list of integers using the bubble sort algorithm. While I was doing this I noticed something weird. This is my code:
#include <iostream>
void bubbleSort(int x) {
bool done;
int list[x] {0};
std::cout << "List:\n";
for (int i=0;i<x;i++) {
std::cout<<i<<':';
std::cin>>list[i];
}
do {
done = true;
for (int i=0;i<x-1;i++) {
if (list[i]>list[i+1]) {
list[i] = list[i]+list[i+1];
list[i+1] = list[i]-list[i+1];
list[i] = list[i]-list[i+1];
done = false;
}
}
} while (not done);
for (int i:list) {
std::cout<<i<<' ';
}
std::cout<<std::endl;
}
int main() {
int n;
std::cout<<"Length of list: ";
std::cin>>n;
bubbleSort(n);
}
If I input a char instead of an int the program outputs numbers leading up to the length of the list then a string of zeros equal to length of the list.
ex: if I input 5 then type 'k' at the input:
1:2:3:4:0 0 0 0 0
My question is, why is it producing this specific output? I would expect an error if it gets the wrong data type. Sorry if my question is confusing. Thanks in advance.
If you enter k when the input is expecting a number. Then the stream will go into an error state.
The problem is that you did not check the state:
std::cin>>n;
// There could be an error in the line above.
// But you did not check for the error.
Also here:
std::cin>>list[i];
// There could be an error in the line above.
// But you did not check for the error.
Try this:
if (std::cin >> n) {
std::cout << "It worked I got the number: " << n << "\n";
}
else
{
std::cout << "Failed to read a number.\n";
}
How does the above work.
Well the result of the operator>> is a reference to a stream. So it reads a value from the stream into n but returns a reference to the stream. This allows you to things like this:
std::cin >> n >> x >> y;
After each operator>> you get a reference to the stream to apply to the next operator>> so you can chain reads together.
When you use a stream in a boolean context (a test like an if or while) it will convert itself to boolean value depending on its internal state. If the internal state is good std::cin.good() then it will return true otherwise it returns false.
So after it completes the operator>> in then converts itself to bool for the if statement. If it is in a good state you know the read worked. If the read failed it would set an internal fail state and good() returns false.
So what happened in your code.
Well the read failed and the state of the stream was set to failed. When a read fails the preferred behavior is that object being read into remain unchanged (this is what happens for POD (standard) types, user defined types this can be a bit more haphazard).
So the value of n remains unchanged.
When you declared n
int n;
You did not define an initial value so it has an indeterminate value. Which means trying to read that value is UB. UB is bad. it means the code can do anything (which it has done). In practical terms (for most systems) it means the variable has an unknowable value and is whatever was left at that memory location from the last variable that used it.
For your specific case:
So you have typed 5 first then k.
So your first read std::cin >> n; worked.
The next read std::cin>>list[i]; failed.
This set the state of the stream to bad. Any subsequent reads do nothing (until you reset the stream state to good). So you are supposed to detect and fix the stream state.
Each subsequent time around the loop the std::cin >> list[i] will do nothing as the stream is in an error state. Which means it will keep its original value (which for this case is defined as zero 0).
Again the correct action here is to read and check the state of the stream. If it fails take corrective action:
if (std::cin >> list[i]) {
// Worked
}
else {
std::cerr << "Bad input. Try again\n";
// reset the state of the stream
// before trying to read again.
std::cin.clear();
if (std::cin >> list[i]) {
std::cerr << "You got it correct this time\n";
}
else {
std::cerr << "User not bright enough to use the app aborting\n";
throw std::runtime_error("Failed Bad User");
}
}
Additional Note
This behavior of streams is good for reading user input. As it allows a natural flow for detecting and writing code for the user to fix the issue. This design is practically the same for all modern languages that have the same pattern.
But this is not a good flow when you have machine input (ie. there are not expected to be any errors in the input and if there was an error there is no way to correct it).
For reading machine input you can set the stream to throw on an error. This allows you to write nice clean easy to read code that when things go wrong (when they should not) then an exception is throw causing the application to correctly terminate (or the exception could be caught).
std::cin.exceptions(std::ios::badbit); // Fail and Bad
So this is the code
#include<iostream>
using namespace std;
int main(){
int a,b;
while(true){
cout<<"Enter the value of a and b ";
cin>>a>>b;
if(a=='|'||b=='|')
break;
else
cout<<"The value of a is "<<a<<"\nThe value of b is "<<b<<endl;
}
}
and the question is Write a program that consists of a while-loop that (each time around the loop) reads in two ints and then prints them. Exit the program when a terminating '|' is entered.
When i enter input like | it prints infinitely "The value of a is and value of b is ". What is the reason for this?enter code here
std::cin (and I think all streams) by default will set an error flag when you try to read into an invalid data type (e.g. here with trying to read a char into an int variable) and that flag will prevent other std::cin to run until the flag is cleared. To rest the stream, use std::cin.clear() to the reset the error flag and then you have to remove the bad input, either through std::cin.ignore() or read into a string buffer or something, from the stream as it will still be there.
Your istream operator >> as_int is failing and really doing nothing so your loop just keeps going. Either input as chars and convert to ints with checks, or or check the stream for errors.
cin>>a>>b;
if( cin.fail( ) )
break;
istream reading after failure
Additionally: If you had have traced into the istream operator you would have seen why it was not blocking, that it had failed. Always trace when something is wrong...
So I'm curious as to why this happens.
int main()
{
bool answer = true;
while(answer)
{
cout << "\nInput?\n";
cin >> answer;
}
return 0;
}
Expected behavior:
0 - Exits program,
1 - Prompts again,
Any non-zero integer other than 1 - Prompts again
Actual behavior:
0 - As expected,
1 - As expected,
Any non-zero integer other than 1 - Infinite loop
From http://www.learncpp.com/cpp-tutorial/26-boolean-values/
One additional note: when converting integers to booleans,
the integer zero resolves to boolean false,
whereas non-zero integers all resolve to true.
Why does the program go into an infinite loop?
In effect, the operator>> overload used for reading a bool only allows a value of 0 or 1 as valid input. The operator overload defers to the num_get class template, which reads the next number from the input stream and then behaves as follows (C++11 ยง22.4.2.1/6):
If the value to be stored is 0 then false is stored.
If the value is 1 then true is stored.
Otherwise true is stored and ios_base::failbit is assigned to err.
(err here is the error state of the stream from which you are reading; cin in this case. Note that there is additional language specifying the behavior when the boolalpha manipulator is used, which allows booleans to be inserted and extracted using their names, true and false; I have omitted these other details for brevity.)
When you input a value other than zero or one, the fail state gets set on the stream, which causes further extractions to fail. answer is set to true and remains true forever, causing the infinite loop.
You must test the state of the stream after every extraction, to see whether the extraction succeeded and whether the stream is still in a good state. For example, you might rewrite your loop as:
bool answer = true;
while (std::cin && answer)
{
std::cout << "\nInput?\n";
std::cin >> answer;
}
Because operator>> fails if the input is not 0 or 1, and when it fails, it does not consume input. So the loop consists of reading the digit and then un-reading it, repeatedly.
Try changing the code like this to see it:
if (cin >> answer) {
cout << answer << endl;
} else {
cerr << "oops" << endl;
break;
}
I'm running myself through a C++ text book that I have as a refresher to C++ programming. One of the practice problems (without going into too much detail) wants me to define a function that can be passed ifstream or cin (e.g. istream) as an argument. From there, I have to read through the stream. Trouble is, I can't figure out a way to have this one function use cin and ifstream to effectively find the end of the stream. Namely,
while(input_stream.peek() != EOF)
isn't going to work for cin. I could rework the function to look for a certain phrase (like "#End of Stream#" or something), but I think this is a bad idea if the file stream I pass has this exact phrase.
I have thought to use function overloading, but so far the book has mentioned when it wants me to do this. I'm probably putting too much effort into this one practice problem, but I enjoy the creative process and am curious if there's such a way to do this without overloading.
eof() does work for cin. You are doing something wrong; please post your code. One common stumbling block is that eof flag gets set after you try to read behind the end of stream.
Here is a demonstration:
#include <iostream>
#include <string>
int main( int, char*[] )
{
std::string s;
for ( unsigned n = 0; n < 5; ++n )
{
bool before = std::cin.eof();
std::cin >> s;
bool after = std::cin.eof();
std::cout << int(before) << " " << int(after) << " " << s << std::endl;
}
return 0;
}
and its output:
D:>t
aaaaa
0 0 aaaaa
bbbbb
0 0 bbbbb
^Z
0 1 bbbbb
1 1 bbbbb
1 1 bbbbb
(EOF can be generated with Ctrl-Z on Windows and Ctrl-D on many other OSes)
Why won't std::cin.eof() work? cin will signal EOF when stdin closes, which will happen when the user signals it with Ctrl+d (*nix) or Ctrl+z (Windows), or (in the case of a piped input stream) when the piped file ends
If you use a stream in a boolean context then it will convert itself into a value that is equivalent to true if it has not reached the EOF and false if an attempt has been made to read past the EOF (not it is also false if there was a previous error reading from the stream).
Since most IO operations on streams return the stream (so they can be chained). You can do your read operation and use the result in the test (as above).
So a program to read a stream of numbers from a stream:
int main()
{
int x;
// Here we try and read a number from the stream.
// If this fails (because of EOF or other error) an internal flag is set.
// The stream is returned as the result of operator>>
// So the stream is then being used in the boolean context of the while()
// So it will be converted to true if operator>> worked correctly.
// or false if operator>> failed because of EOF
while(std::cin >> x)
{
// The loop is only entered if operator>> worked correctly.
std::cout << "Value: " << x << "\n";
}
// Exit when EOF (or other error).
}