`cin.clear()` leaves the input stream in failure state - c++

I am reading the book 'Accelerated C++', and I am unable to reproduce the results for their read homework problem even after exactly copying their code on my machine. The basic problem is about using cin.clear() to change the failure state of the inpute stream after the use of EOF to indicate that all the grades have been entered. Authors suggest Ctrl+D on linux systems for EOF. I already saw this and this but they couldn't solve my problem.
Here is my minimal working example:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
string name, city;
vector<double> homework;
cout << "Enter your name : " ;
cin >> name;
cout << "Hello " + name + "!" << endl;
cout << endl;
cout << "Enter your grades" << endl;
if (cin)
{
homework.clear();
double x;
while (cin >> x)
{
homework.push_back(x);
}
cin.clear();
}
cout << endl;
cout << "Enter your city : " ;
cin >> city ;
cout << "You live in " + city << endl;;
return 0;
}
After entering all the homework, I hit Ctrl+D and then I expect that I would now be given chance to enter city name. But the program just ends after printing the two strings at the end of my code. What is wrong with my understanding of cin.clear()? I would also like to point out that using cin.ignore() after cin.clear() doesn't help either.

On fail you need to clear the flags and ignore all the bad input.
Include #include <limits> for std::numeric_limits.
if ( std::cin.fail( ) )
{
std::cin.clear( );
std::cin.ignore( std::numeric_limits<std::streamsize>::max( ), '\n');
}
If you want a way to exit the loop use a value that you can test for (like -1). When you receive that value, exit the loop.
double value{ 0 };
while( std::cin >> value && value != -1 )
homework.push_back( value );
if ( std::cin.fail( ) )
{
std::cin.clear( );
std::cin.ignore( std::numeric_limits<std::streamsize>::max( ), '\n');
}
Edit:
I didn't see that you were trying to end the stream with EOF.
Read this answer to figure out how to accomplish this.
How to resume input stream after stopped by EOF in C++?

Related

How do I make it so my program doesn't loop when adding new entries to a txt file

I am not sure where I put the char command declaration where I wont get a "Not defined in this scope" error and it will loop through accepting a new char command the next time the program loops.
I tried putting it inside of the do loop but then it said that char was not defined in that scope, I then put it right after the int main function and when entering A as a command it infinitely loops my add_entry function without allowing user input.
Do I have to pass by reference maybe? Or pass by value?
My file that holds all function definitions
#include "main.h"
using namespace std;
int syntax::add_entry()
{
cout << "Enter a concept name: ";
cin.get(name, SIZE);
cout << endl << "Enter an example of the syntax: ";
cin.get(example,SIZE);
cout << endl << "Enter a description of the syntax: ";
cin.get(desc,SIZE);
cout << endl << "Enter a difficulty rating from 1-10: ";
cin.get(diff,SIZE);
cout << endl << "Enter a usefulness rating from 1-10: ";
cin.get(use,SIZE);
//open and write to the file
ofstream myfile;
myfile.open("data.txt");
myfile << "Name: " << name << endl;
myfile << "Example of syntax: " << example << endl;
myfile << "Description of syntax: " << desc << endl;
myfile << "Difficulty rating from 1-10: " << diff << endl;
myfile << "Usefulness rating from 1-10: " << use << endl;
myfile.close();
return 0;
}
int syntax::display_entry()
{
ifstream myfile("data.txt");
/*
char name[SIZE];
char example[SIZE];
char desc[SIZE];
char diff[SIZE];
char use[SIZE];
*/
if(myfile.is_open())
{
while(myfile >> name >> example >> desc >> diff >> use)
{
std::cout << name << ", " << example << ", " << desc << ", " << diff << ", " << use;
}
myfile.close();
}else
cout << "File is not open" << endl;
std::cin.get();
return 0;
}
my main .cpp file
#include "main.h"
using namespace std;
int main()
{
char command;
syntax c;
do{
cout << "Welcome to the C++ concept syntax user database." << endl;
cout << "Choose one of the following commands: " << endl;
cout << endl << endl;
cout << "A) Add a new entry B) Display all entrys C) Search for difficulty D) Exit: ";
cin >> command;
cout << endl;
if(command == 'A' || command == 'a')
{
c.add_entry();
}
else if(command == 'B' || command == 'b')
{
c.display_entry();
}
else if(command == 'D' || command == 'd')
{
cout << "Quitting program, Thank you for using" << endl;
}
}while(command != 'D' || command != 'd');
return 0;
}
my .h file
#include <iostream>
#include <fstream>
#include <cstring>
#include <cctype>
using namespace std;
class syntax
{
public:
const static int SIZE = 50;
char name[SIZE];
char example[SIZE];
char desc[SIZE];
char diff[SIZE];
char use[SIZE];
int display_entry();
int add_entry();
private:
};
You need to read and understand about "formatted input" and "unformatted input". Please check here.
Formatted input is done using the extractor operator >>. It reads characters from a stream and formats them to the expected variable type. If you write int x; std::cin >> x and you enter the number 12, so the digits/characters '1' and '2', your input will be formatted / converted to an integer value 12.
It is important to understand that formatted input
ignores leading white space
stops any conversion when encountering white space (but does not extract it from the stream)
Meaning, if you enter 12 and then press the enter-key, the characters '1' and '2' will be extracted from the stream, but the newline 'n' will not be consumed or extracted from the screen and is still available.
This default behavior can be addapted by setting certain flags.
Now, if we look at "unformatted input" functions, like get, it will read all kind of characters, including spaces and so on until it hits the specified delimiter, which is '\n' per default. For the get function, the delimiter '\n' will not be extracted. So, it is still in the stream. This is in contrast to the getline function which would extract the '\n' from the stream (but not store it).
All this you can read in the linked description.
And now, the root cause for all you problems, is also written in the description:
If no characters were extracted, calls setstate(failbit)
Then, let us look on the order of events
You enter a 'a', becuase you want to add an entry
The 'a' will be extracted and the '\n' is still in the stream
In function "add_entry" you call "get"
Get will try to read charcters, until it finds a newline '\n'
But, as a leftover from the previous operation, it will immediately see the '\n' , and hence store no other data at all, and consequently sets the failbit of the stream. All the following calls to std::cin will do nothing, because the failbit of the stream is set.
The functions returns to main and the failbit is still set
The next call cin >> command; will do nothing and will especially not modify the "command" variable. This will still contain an 'a'
And then the loop runs forever
You have an additional bug in the "while" condition. This must be corrected to: ´while (command != 'D' && command != 'd');´
Now, what to do.
First, and very important, for any IO-function you need to check, if it worked or not. There are functions to read the iostate of the stream. But c++ makes life easier. The bool-operator and the not-operator are overwritten and will return state information. If you want to know, if any IO operation was successful, the you can write something like if (std::cin) ....
Very convenient. But must be used.
And since IO operations return mostly a reference to the stream for which they were called, you can write if (cin >> command) . . . . This will first call the extraction operator. This will return a reference to the stream and for that you can use an if statement, because of the overwritten bool-operator.
But how to overcome the nasty problem with the '\n' in the stream, which is often there? There are basically 2 functionalities:
Function ignore. Will ignore all/a number of characters, until a delimiter is hit.
Function/manipulator std::ws. Will eat all white spaces.
I recommend to add one time cin >> std::ws; at the top of your "add_entry" routine and then you must change all get functions to getline. If not, you would need to add std::ws before each get statement.
And again, for each IO function, check the status! For example if (!cin.getline(example, SIZE)) .... do something, show error
And in the future. For any transition from formatted to unformatted input, use std::ws
And, do never forget to read the documentation carefully.
Have fun!

loop involving "cin.fail()" running multiple times

I am having trouble with the following code. It is meant to keep asking for a valid input until an integer or double is inputted. It works as intended for characters, however when I input a string of length more than 1, it will run the loop multiple times. For example, the input "hello" with cause "Please enter a valid number" to be printed 5 times. Interestingly "h llo" will only print the sentence 4 times.
int gamenumber;
while(true)
{
cin >> gamenumber;
if(cin.fail())
{
cout << "Please enter a valid number" << endl;
cin.clear();
cin.ignore();
} else
break;
I did manage to fix this issue by replacing "cin.ignore()" with "cin.ignore(1000, '\n')".
But regardless, it's bugging me that I don't understand why "cin.ignore()" alone doesn't fix this? Is there a way to fix the above code without using "cin.ignore(1000, '\n')"? (This is part of a homework assignment, and we may not be allowed to use "cin.ignore(1000, '\n')")
Thank you!
You need use ignore with the overloaded one, see this anser here.
Or you can just need to run getline to drain the contents, but this way is slower and unnecessary.
#include <iostream>
#include <string>
int main()
{
double n;
while( std::cout << "Please, enter a number\n"
&& ! (std::cin >> n) )
{
std::cin.clear();
std::string line;
std::getline(std::cin, line);
std::cout << "I am sorry, but '" << line << "' is not a number\n";
}
std::cout << "Thank you for entering the number " << n << '\n';
}

std::cin infinite loop from invalid input [duplicate]

This question already has answers here:
Infinite loop with cin when typing string while a number is expected
(4 answers)
Closed 6 years ago.
Please read the following code:
#include <iostream>
#include <cstdlib>
int main() {
std::cout << "Please input one integer." << std::endl;
int i;
while (true) {
std::cin >> i;
if (std::cin) {
std::cout << "i = " << i << std::endl;
break;
} else {
std::cout << "Error. Please try again."<< std::endl;
std::cin.ignore();
std::cin.clear();
}
}
std::cout << "Thank you very much." << std::endl;
std::system("pause");
return 0;
}
When I give std::cin an invalid input, such as w, then Error. Please try again. is outputed infinitely.
I thought std::cin.ignore would blank the input stream, and std::cin.clear would resume it to normal state. So why does the infinite loop happen?
By default, std::basic_istream::ignore() ignores only 1 character:
basic_istream& ignore( std::streamsize count = 1, int_type delim = Traits::eof() );
(From http://en.cppreference.com/w/cpp/io/basic_istream/ignore)
More idiomatic use for your case seems to be the one from the example there:
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
Also, note that you want to call clear() before the ignore() call, so the input extraction of ignore() will succeed instead of returning immediately.

Converting char to int when asked to enter an integer and checked with isdigit

So recently, I came across using isdigit as a way to check to see if an entered value for an int is actually an integer, rather than a string or a char.
However, when I wrote a short program to play around with that, the program failed to execute from that point on.
EDIT: I also in the program wanted to take the invalid data and convert it to a different data type.
Here is the code:
#include <iostream>
#include <sstream>
#include <string>
#include <cctype>
using namespace std;
int main()
{
int enterCFN;
char revisit;
int review(0);
cout << "Enter a digit: ";
cin >> enterCFN;
bool y = isdigit(enterCFN);
if (y == false)
{
// This is the data conversion section
revisit = enterCFN;
revisit = review;
cout << review << "\n";
}
else
{
cout << enterCFN << "\n";
}
return 0;
}
Is there anyone who can correct my error and show me what I'm doing wrong?
enterCFN is an int. It stores a number. isdigit() checks if a character represents a number. These are not the same thing: for example 32 is a number but char(32) means ' ' (space).
What you want instead is this:
if (cin >> enterCFN)
That will take the input from the user and check if it is valid all at once. No need for isdigit().
isdigit() checks if a given character is one of 0-9
For validating integer do something like following:
std::cout << "Enter a digit: ";
std::cin >> enterCFN ;
while (1)
{ if ( std::cin >> enterCFN )
{
// good input
break ;
}
else
{
std::cout << "Enter a digit: ";
// clear stream flags set due to bad input
std::cin.clear();
// get rid of the bad input.
// ignore the rest of the line
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}

How do I sanitise cin?

Say I have a program that takes in integers. How do I stop the program from falling apart if the user enters an out of range number, or a letter or something?
The cin's base class is std::basic_istream. The input stream indicates a recoverable error in case it cannot extract the requested data from the stream. In order to check for that error bit, std::basic_istream::fail() method must be used — it returns true if there was a failure or false if everything is alright. It is important to remember that if there is an error, the data is left in the stream and, of course, the error bit(s) must also be cleared using std::basic_istream::clear(). Also, a programmer must ignore incorrect data, or otherwise an attempt to read something else will fail again. For that purpose, std::basic_istream::ignore() method can be used. As for the valid range of values, it must be checked manually. Okay, enough theory, here is a simple example:
#include <limits>
#include <iostream>
int main()
{
int n = 0;
for (;;) {
std::cout << "Please enter a number from 1 to 10: " << std::flush;
std::cin >> n;
if (std::cin.fail()) {
std::cerr << "Sorry, I cannot read that. Please try again." << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
continue;
}
if (n < 1 || n > 10) {
std::cerr << "Sorry, the number is out of range." << std::endl;
continue;
}
std::cout << "You have entered " << n << ". Thank you!" << std::endl;
break;
}
}
Hope it helps. Good Luck!
I prefer reading the input as strings, and then sanitizing them with boost::lexical_cast<>:
#include <boost/lexical_cast.hpp>
#include <iostream>
#include <string>
int main () {
std::string s;
while( std::cin >> s) {
try {
int i = boost::lexical_cast<int>(s);
std::cout << "You entered: " << i << "\n";
} catch(const std::bad_cast&) {
std::cout << "Ignoring non-number: " << s << "\n";
}
}
}
Postscript: If you are allergic to Boost, you can use this implementation of lexical_cast:
template <class T, class U>
T lexical_cast(const U& u) {
T t;
std::stringstream s;
s << u;
s >> t;
if( !s )
throw std::bad_cast();
if( s.get() != std::stringstream::traits_type::eof() )
throw std::bad_cast();
return t;
}
something like this should do you need to clear the buffer after checking aswell if i remember right
if (cin.fail())
{
cout<<"need to put a number"<<endl;
cin.clear();
cin.ignore();
}
If You dont want to add libraries to your code you could also use do..while() statements.
in your do while you will ask for user input and then receive it to your variable then in the while part you will be able to check that this is the data you are expecting if not continue to ask for the data.
just another option ....even though the answer already mentioned should work more than adequately
You can use the following code for simplest and fast checking of valid input in int :
#include "stdafx.h"
#include <iostream>
using namespace std;
int main()
{
int intb;
while( !( cin>>intb ) ){
cin.clear ();
cin.ignore (1000, '\n');
cout<<"Invalid input enter again: "<<endl;
}
cout<<"The value of integer entered is "<<b<<endl;
return 0;
}
The while loop keeps on iterating until it gets the right input.
cin.clear() changes the error control state.
cin.ignore() removes clear the input stream so that new input can be taken again. If not done thw while loop will be in infinite state.