How do I sanitise cin? - c++

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.

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 ;)

Check for Empty sstream

I am wrote a function that can replace cin for integers and potentially doubles, that includes error checking capabilities. Using cin.fail() I was able to check for most cases, but that didn't cover the case where the input was followed by a string without a space. For example, "23tewnty-three." The following code accommodates this.
int getUserInt(string prompt = "Enter an integer: ", string errorMessage "Error: Invalid Input") {
const int IGNORE_MAX = 100;
int userInt = 0;
bool isContinue = true;
do {
// initialize and reset variables
string inputStr;
istringstream inputCheck;
userInt = 0;
// get input
cout << prompt;
cin >> inputStr;
inputCheck.str(inputStr);
// check for valid input
inputCheck >> userInt;
if (!inputCheck.fail()) {
// check for remaining characters
if (inputCheck.eof()) { // Edit: This is the section that I tried replacing with different code (made code compilable in response to comment)
isContinue = false;
}
else {
cout << errorMessage << endl;
}
}
else {
// reset cin and print error message
cin.ignore(IGNORE_MAX, '\n');
cin.clear();
cout << errorMessage << endl;
}
} while (isContinue);
return userInt;
}
This code works, but the reason I am posting this to Stack Overflow instead of Code Review is because my main question is about why some of code didn't work as I expected. The following is what I tried in place of inputCheck.eof() in the previous code. My questions are what are the differences between the following code? Why didn't methods 2) and 3) work? and which method is preferred?
inputCheck.eof()
inputCheck.peek() == EOF
inputCheck.str().empty()
inputCheck.rdbuf()->in_avail() == 0
1) and 4) worked as expected, but 2) and 3) did not.
Edit:
I believe 3) didn't work as expected because inputCheck.str() returns what was contained in inputStr when inputCheck.str(inputStr) was called. However, I have no idea why inputCheck.peek() == EOF didn't work.
If this is relevant information, I am compiling and running on windows through bash g++.
For every prompt you provide, you can expect your user to press Enter. Obtain input as a string, then try to convert. (Don’t try to convert from cin.)
Bonus: here’s a function to perform conversion.
template <typename T>
auto string_to( const std::string & s )
{
T value;
std::istringstream ss( s );
return ((ss >> value) and (ss >> std::ws).eof())
? value
: std::optional<T> { };
}
You’ll need C++17 for that, or to #include <boost/optional.hpp> instead.
Now:
std::cout << "Enter an integer! ";
std::string s;
getline( std::cin, s );
auto x = string_to <int> ( s );
if (!x)
{
std::cout << "That was _not_ an integer.\n";
}
else
{
std::cout << "Good job. You entered the integer " << *x << ".\n";
}
No more worrying about clearing or resetting cin. Handily perform some loops (such as allow user three attempts before quitting). Et cetera.

how to allow multiple inputs in case of an incorrect data type entry in cpp?

I have a program which generates random number and asks user to keep guessing it until he/she gets it right. I want it to keep accepting new values even if i incorrectly enter any other data type by handling the error cases.
My problem is that when i am trying to run the below program, as soon i input a character and hit enter, it goes into an infinite loop. I tried using cin.ignore() and cin.clear() but that just makes the program stop after the first entry.
Can anyone please help me understand what is going on and how to achieve the desired output? Thanks in advance.
#include <iostream>
#include <cstdlib>
#include <time.h>
using namespace std;
int main()
{
int secret_num, guess;
srand(time(NULL));
secret_num=rand() % 101 + 0;
cout<<"Enter your guess between 0 and 100: ";
do
{
if(!(cin>>guess))
{
cout<<" The entered value is not an integer"<<endl;
}
else if( isnumber(guess))
{
if(guess>secret_num)
cout<<"Too high";
else if(guess<secret_num)
cout<<"too low";
cout<<endl;
}
}
while(secret_num!=guess);
if((guess==secret_num)| (isnumber(guess)))
{
cout<<"yes the correct number is "<<secret_num<<endl;
}
return 0;
}
Edit: Here is a screenshot of what the output looks like with cin.clear() and cin.ignore(1000,'\n') in my code, when i enter a number after entering character twice.
if (!(cin >> guess))
{
cout << " The entered value is not an integer" << endl;
cin.clear(); // clear must go before ignore
// Otherwise ignore will fail (because the stream is still in a bad state)
cin.ignore(std::numeric_limits<int>::max(), '\n');
}
By default cin.ignore will ignore a single character. If they type more than 1 char, it won't be enough, that's why I've modified it a bit.
if ((guess == secret_num) | (isnumber(guess)))
| is a bitwise operator [OR]
|| is the logical operator [OR]
But I think what you actually want is && (AND)
if ((guess == secret_num) && (isnumber(guess)))
There're several problems.
You should use cin.clear() and cin.ignore() as #José suggested.
What's isnumber()? I guess it's returning false so no hint message (i.e. "Too high" and "too low") is printed out, looks like it stops although it's just waiting the next input. And isnumber() doesn't make sense to me. guess has been declared as an int, it has to be a number, doesn't it?
if((guess==secret_num)| (isnumber(guess))) is unnecessary here. The loop won't end until the user input the correct number, this condition should have been statisfied.
You can use clear and flush
if(!(cin>>guess))
{
cout<<" The entered value is not an integer"<<endl;
cin.clear();
fflush(stdin);
}
This works if you are reading from console. Otherwise you can go with #José answer.
I would change the logic inside your loop as there are some useless tests. This works for me:
#include <iostream>
#include <limits>
#include <cstdlib> // You may take a look at <random> and <chrono>
#include <time.h>
using std::cout;
using std::cin;
int main() {
srand(time(NULL));
int secret_num = rand() % 101;
cout << secret_num << '\n';
cout << "Enter your guess between 0 and 100:\n";
int guess = -1;
do {
cin >> guess;
if ( cin.eof() )
break;
if ( cin.fail() ) {
cout << "The entered value is not an integer, please retry.\n";
// clear the error flag
cin.clear();
// ignore the rest of the line
cin.ignore(std::numeric_limits<int>::max(),'\n');
// clear the value of the variable
guess = -1;
continue;
}
// now we know that guess is a number
if ( guess > secret_num )
cout << "Too high\n";
else if ( guess < secret_num )
cout << "Too low\n";
else {
cout << "Yes the correct number is " << secret_num << std::endl;
break;
}
} while ( true );
return 0;
}

How to throw an std::iostream failure in C++?

How do I manually throw an std::iostream::failure?
I have a try-catch loop that catches an exception when the user tries to input a non-integer string, however it does not throw an exception if the user tries to input a float since it will try to read everything before the decimal point in a float value. My solution is to manually throw the exception if there is still data remaining in the stream, how do I do that?
/*
Sample Implementation Code in C++
Handling Inputs from User in C++
This code only stops running when the user
inputs the appropriate values. Otherwise, the program
will continue asking the user for input.
*/
#include <iostream>
#include <limits> //numeric_limits
#include <stdexcept>
int main() {
std::cin.exceptions(std::ios::failbit); // set exceptions to be thrown when a failbit is set
int num = 0;
int den = 0;
while (true) {
try {
std::cout << "Enter numerator: ";
std::cin >> num;
if(std::cin.peek() != '\n') {
//HOW TO DO THIS PART?
std::iostream::failure e;
throw e;
}
std::cout << "Enter denominator: ";
std::cin >> den;
std::cout << "The quotient is " << num/den << std::endl;
} catch (std::iostream::failure& e){
std::cout << "Input should be an integer." << std::endl;
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
return 0;
}
Apparently it's as simple as:
throw std::iostream::failure("");
the important thing I forgot is the empty string ("") since it has a constructor that takes a string argument but not a void argument.

C++ input validation

I am beginning C++ programming, and have to do a lot of input validation. I have found this function that seems universally applicable, but am having trouble with one aspect; If I were to type -90, the program doesn't give an error. my question(s) are:
1. How can I add the circumstance that input cannot be <= 0?
2. Is there a better way to limit users input? Maybe a library within C++?
Thank you for any help, or advice.
#include <ios> // Provides ios_base::failure
#include <iostream> // Provides cin
template <typename T>
T getValidatedInput()
{
// Get input of type T
T result;
cin >> result;
// Check if the failbit has been set, meaning the beginning of the input
// was not type T. Also make sure the result is the only thing in the input
// stream, otherwise things like 2b would be a valid int.
if (cin.fail() || cin.get() != '\n')
{
// Set the error state flag back to goodbit. If you need to get the input
// again (e.g. this is in a while loop), this is essential. Otherwise, the
// failbit will stay set.
cin.clear();
// Clear the input stream using and empty while loop.
while (cin.get() != '\n')
;
// Throw an exception. Allows the caller to handle it any way you see fit
// (exit, ask for input again, etc.)
throw ios_base::failure("Invalid input.");
}
return result;
}
Usage
inputtest.cpp
#include <cstdlib> // Provides EXIT_SUCCESS
#include <iostream> // Provides cout, cerr, endl
#include "input.h" // Provides getValidatedInput<T>()
int main()
{
using namespace std;
int input;
while (true)
{
cout << "Enter an integer: ";
try
{
input = getValidatedInput<int>();
}
catch (exception e)
{
cerr << e.what() << endl;
continue;
}
break;
}
cout << "You entered: " << input << endl;
return EXIT_SUCCESS;
}
You can use functions to validate
template <typename T>
T getValidatedInput(function <bool(T)> validator) {
T tmp;
cin >> tmp;
if (!validator(tmp)) {
throw ios_base::failure("Invalid input.");
}
return tmp;
}
Usage
int input = getValidatedInput<int>([] (int arg) -> bool {
return arg >= 0;
});
std::istream::operator >> is defined in terms of strtol, strtoul, and cousins*, which unfortunately all invariably accept a minus sign even for unsigned types.
Essentially all you can do is accept signed int input and compare the result to zero. std::cin.setf( std::ios::failbit ) artificially raises a conversion exception, so you can sort-of emulate how the conversion function should behave on error, but that might not really be much help.
* operator >> is defined in terms of std::num_get, which is defined in terms of scanf, which is defined in terms of strto*. Everyone just passed the buck, but strtoul is pretty surely defective.
Use unsigned int as a template parameter.
Only you can setup a rules about what input is valid and what is not.
I hope this is what you're after, it exit's upon entering zero, but will display negative numbers. It throws an exception error due to the input catch method.
#include "stdafx.h"
#include <iostream>
using namespace std;
void inputcatch()
{
cin.clear();
cin.ignore(cin.rdbuf()->in_avail());
}
int main()
{
int input;
bool quit = false;
while (!quit)
{
cout << "Enter number" << endl;
cin >> input;
if (cin.fail())
{
inputcatch();
cout << "incorrect input" << endl;
}
else if (input == 0)
{
quit = true;
}
else
{
cout << "your number: " << input << endl;
}
}
return 0;
}