Why does this cin loop never end? - c++

In the following code, if the user inputs something that is not an int, the program goes into an infinite loop. Why does this happen, and what should I do to fix it?
#include <iostream>
#include <string>
using namespace std;
int main()
{
int i;
char str[100];
while (!(cin >> i))
{
gets(str);
cout << "failure read!" << endl;
}
cout << "successful read!" << endl;
return 0;
}

Clear the error state:
int main()
{
int i;
char str[100];
while (!(cin >> i))
{
cin.clear();
cin.getline(str,100);
cout << "failure read!" << endl;
}
cout << "successful read!" << endl;
return 0;
}

I think that you want to replace the while loop with an if statement, with this loop, you'll continuously read from cin while an error occurs. However, cin is structured so that after an error occurs, you must manually clear the error state, and since you're not doing that here this will go into an infinite loop. Using an if statement tries to read a value and then let's you know whether or not it succeeded.
Additionally, this really isn't a good way to read from cin. It's brittle and any invalid input can totally take down your program, since gets is inherently unsafe. For a discussion of a safer and more robust way to get input in C++, check out http://www.stanford.edu/class/cs106l/course-reader/Ch3_Streams.pdf

Related

std::cin failure leading to looped if statement in while loop

So I figure I'll put this here since I had to traverse a lot of docs and forums to find the definitive answer. I was trying to get input from the user and check if the input was an integer using isdigit() in an if statement. If the if statement failed the program would output an error message. Although, when a nondigit character was entered the program would loop through the error message endlessly. Here's that code:
int guess = -1;
while (game.getCurQuestion() <= 4) {
std::cout << "Guess: " << game.getCurQuestion() + 1 << std::endl;
std::cin >> guess;
if(isdigit(guess))
{
game.guess(guess);
else
{
std::cout << "Error\n"; //this would be looped endlessly
}
}
std::cout << "You got " << game.getCorrect() << " correct" << std::endl;
return 0;
}
NOTE: Solved, only posted to include my solution. Feel free to correct if I stated anything incorrectly.
The posted way will fail sometimes and will cast the doubles to integers if any doubles are input.
Use something like the following
int getIntInput() {
try {
std::string input;
std::cout << "\nPlease Enter a valid Integer:\t";
std::cin >> input;
size_t takenChars;
int num = std::stoi(input, &takenChars);
if (takenChars == input.size()) return num;
} catch (...) {}
return getIntInput();
}
Problem: The program kept hold of the non-integer value stored in the cin buffer. This leads to the program never leaving the error message.
Solution:
Use std::cin.fail() to check if the input matches the variable data type. I.E. int was the expected input but the user entered a char. In this case std::cin.fail() would be true.
In the case of std::cin.fail(), use std::cin.clear() and std::cin.ignore(std::numeric_limits<int>::max(), 'n') std::cin.clear() will clear the error flag. The std::cin.ignore(std::numeric_limits<int>::max(), 'n') will ignore any other input that is not an integer and will skip to the new line. Effectively progressing the program.
The solution implemented in my code looks like this:
int guess = -1;
while (game.getCurQuestion() <= 4) {
std::cout << "Guess: " << game.getCurQuestion() + 1 << std::endl;
std::cin >> guess;
if (std::cin.fail())
{
std::cout << "Please enter a valid number\n";
std::cin.clear();
std::cin.ignore(std::numeric_limits<int>::max(), '\n');
}
game.guess(guess);
}
Hope this helps and that it saves some people the tedious research because of never learning std::cin error handling! Note: I'm aware my implementation skips the current move, call it punishment ;)

Can anyone help identify why this wont execute properly? IF promblems with cast

#include <iostream>
#include <fstream>
using namespace std;
int run_t = 0;
char q_mos;
char i_pstring;
int main () {
cout << "Would you like to write to the temporary datapcku database?\nSelect Y/N\n";
cin >> q_mos;
if(q_mos = char(Y)){ //for some reason I am having time resolving the value of Y
while(run_t=0){
cout << "Running Input Operations.\n";
cout << "Please provide me with a Question so it can be achrived in the Active DB(Directory)\n";
cin >> i_pstring;
cout << "Please tell me the answer...\n";
cout << i_pstring;
}
run_t=1;
} else {
run_t=1;
cout << "Booting into main operations...\n";
}
cout << "At diagnostic Boot menu, prepare for diagnostic on system config orginaztional routines.\n";
ofstream binlib;
binlib.open ("datapcku.bin", ios::app | ios::binary );
binlib << "Writing this to a file.\n";
binlib.close();
while(1){}
return 0;
}
As is is apparent I wanted to use my run_t variable to control complete program maneuverability but I am having a time executing q_mos to cin input and I can not understand why the logic appears to be failing, as in the simple while loop following the q_mos comparison wont execute even one I get inside the block.
Do i need to convert q_mos to a string? And what could be affect my run_t variable while loop.
A couple of things are wrong.
In your if(q_mos = char(Y)) statement,
a) you are assigning, not comparing (use == instead of =). This also applies to your while loop.
b) replace char(Y) with 'Y', as you are passing it at the moment, Y is perceived to be a variable.

Why does this cause in infinite loop with chars but not doubles?

I feel like im doing something really silly wrong. I just want the program to tell the user when they are entering non-doubles, and continue to loop back to the cin where you enter a value.
I want the user to input any number. Then essential do this trivial math and repeat. Its working fine in that regard, the problem comes when some unexpected input like a char gets entered. Then the input somehow sends it into a loop where it loops the math problem, instead of just telling the user that they must type a number and looping back to cin type in a new number.
#include <iostream>
#include <cstdlib>
using std::cout; using std::cin; using std::endl;
long double domath(long double i)
{
cout << i << "/" << 2 << "=" << i/2 << endl;
cout << i/2 << "*" << 10 << "=" << (i/2)*10 << endl << endl;
cout << 5 << "*" << i << "=" << 5*i << "\n\n";
return 0;
}
int main()
{
long double in = 0;
while(true)
{
cin >> in;
if (cin.fail()) {
in = char(int(in));
}
domath(in);
}
system("pause>nul");
return 0;
}
You don't clear the cin in case of fail, and it infinitely tries to parse wrong input to double, failing every time. You need to clear the buffer in case of error:
if (cin.fail()) {
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
in = char(int(in));
}
Also, can't understand what you're trying to achieve with
in = char(int(in));
in is a long double variable and will hold the last value you assigned to it, no need to "convert" it to do math.
Couldn't you try doing something like this?
int x;
if(std::cin >> x)
doSomethingCool(x);
else
std::cout << "Error, not a valid integer!" << std::endl;
Exit your loop on bad input.
I think this just feels more natural/looks cleaner than clearing the buffer and all the other jazz. Just my opinion.
if (cin >> x) - Why can you use that condition?
edit: Bul's answer is still a good one though.

Testing for an integer in c++

I'm trying to write a c++ program that tests each input integer, and stops if the input is invalid.
Here is my code, without the testing part:
#include <iostream>
#include <stdlib.h>
using namespace std;
int main()
{
int i;
do
{
cout << "\nPlease enter an integer: ";
cin >> i;
cout << endl << i << endl;
} while(i != 0);
system("Pause");
return 0;
}
How can I test the input for validity?
The easiest is to use std::getline to read a whole line of input into a std::string, and then test whether that string is a valid integer specification.
It's also possible to do this by testing the failure state of cin, and clearing it, but that way lies an assortment of complications that you don't want.
In order to test the string you can use a high level std::istringstream (just read from it and test its failure state after) or, more efficient but a little more complicated, strtol from the C library (the latter is what a C++ stream uses internally).
You need to test whether a string is an integer without crashing.
You can do this with strtol(). It converts the string to an integer, and reports on the first character that is not a legal char for a number. No invalid characters means the entire string was an integer.
There is a good description and example of how to use it here:
http://www.tutorialspoint.com/c_standard_library/c_function_strtol.htm
#include <iostream>
#include <stdlib.h>
using namespace std;
int main()
{
int i;
do
{
cout << "\nPlease enter an integer: ";
while(!(cin >> i))
{
cin.clear();
cin.ignore();
cout << "\nInput was invalid, please re-enter: ";
}
cout << endl << "The integer is: " << i << endl;
} while(i != 0);
system("Pause");
return 0;
}

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.