Checking cin input stream produces an integer
You can check like this:
int x;
cin >> x;
if (cin.fail()) {
//Not an int.
}
Furthermore, you can continue to get input until you get an int via:
#include <iostream>
int main() {
int x;
std::cin >> x;
while(std::cin.fail()) {
std::cout << "Error" << std::endl;
std::cin.clear();
std::cin.ignore(256,'\n');
std::cin >> x;
}
std::cout << x << std::endl;
return 0;
}
EDIT: To address the comment below regarding input like 10abc, one could modify the loop to accept a string as an input. Then check the string for any character not a number and handle that situation accordingly. One needs not clear/ignore the input stream in that situation. Verifying the string is just numbers, convert the string back to an integer. I mean, this was just off the cuff. There might be a better way. This won't work if you're accepting floats/doubles (would have to add '.' in the search string).
#include <iostream>
#include <string>
int main() {
std::string theInput;
int inputAsInt;
std::getline(std::cin, theInput);
while(std::cin.fail() || std::cin.eof() || theInput.find_first_not_of("0123456789") != std::string::npos) {
std::cout << "Error" << std::endl;
if( theInput.find_first_not_of("0123456789") == std::string::npos) {
std::cin.clear();
std::cin.ignore(256,'\n');
}
std::getline(std::cin, theInput);
}
std::string::size_type st;
inputAsInt = std::stoi(theInput,&st);
std::cout << inputAsInt << std::endl;
return 0;
}
My code fails to verify input as an integer
If the user does not type in an integer, your code enters an infinite recursive loop that it does not recover from, eventually overflowing the call stack.
Try something more like this instead:
int getUserInput()
{
int number;
cout << "Enter a number between 1 - 100: ";
do
{
// if the user input a valid integer, process it
if (cin >> number)
{
if (number >= 1 && number <= 100)
break;
cout << "Number out of range, try again: ";
}
else
{
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(), '\n');
cout << "Invalid input, try again: ";
}
}
while (true);
return number;
}
Checking input is an integer
If you need to check for a positive integer, you probably need
to convert the text to an integer as well. You should do both
at once; something along the lines of:
std::string line;
if ( !std::getline( std::cin, line ) ) {
// no input available...
} else {
std::istringstream parser( line );
int userNumber;
if ( parser >> userNumber >> std::ws
&& parser.get() == EOF
&& userNumber > 0 ) {
// All OK...
} else {
// Some error in the input.
}
}
It's also possible to use strtol
, if you have the string from
elsewhere. Error detection is a bit tricky, because strtol
has some strange semantics in some cases:
int
getPositiveInteger( std::string const& input )
{
char const* end;
errno = 0;
long results = strtol( input.c_str(), &end, 10 );
if ( end != input.c_str() ) {
while ( isspace( static_cast<unsigned char>( *end) ) ) {
++ end;
}
}
return (errno == 0
&& end != input.c_str()
&& *end == '\0'
&& results > 0
&& results <= INT_MAX)
? results
: -1;
}
(I've returned -1 in case of an error.)
You'll notice the number of conditions you have to test to be
sure that stdtol
has worked correctly.
Input data type check in loop not working as intended (C++)
Your main problem is that you only clear the error condition but never flush the offending input, so the input stream stays at the erroneous characters. The common way is to read (and discard) a full line for a failed conversion:
while (true) {
std::cout << ">>> ";
std::cin >> input;
std::cout << std::flush;
if (std::cin.eof()) { // do not try to read past an eof!
input = 0;
break;
}
if (std::cin.fail() || input < 0) {
std::string line;
std::cin.clear(); // reset the fail flag
std::getline(std::cin, line); // read until end of line
std::cout << "Failed";
continue;
}
break;
}
try and except, but in c++
An exception
is a problem that arises during the execution of a program. Allowing the user to stop giving more input is not a problem. Your logic should handle. There are multiple ways to do it.
Try..catch
is always there for you.
One way could be parsing the input to check if the input is an int. If not, break
the while
.
Another way could be as shown below.
#include <iostream>
using namespace std;
int main() {
int num;
cin >> num;
while(cin.fail()){
//your logic goes here
cin.clear();
cin.ignore(numeric_limits<int>::max(), '\n');
cin >> num;
};
return 0;
}
input stream in C++. A little confusion with cin unget() function
Lets take a closer look at skip_to_int
if (cin.fail()) {
if the last input was bad
cin.clear();
clear the flags and look for the next good data
for (char ch; cin>>ch; ) {
get a character
if (isdigit(ch) || ch=="-") {
if character is a character we want
cin.unget();
put it back into the stream
return;
exit the function!!!
}
otherwise loop back around to get the next character
}
no more characters, exit the loop
}
error("no input");
Immediately following the unget
, the function returns, ending the loop along with the function.
Checking for legitimate integer input in c++
Assuming that you can't use boost::lexical_cast
, you can write your own version:
#include <sstream>
#include <iostream>
#include <stdexcept>
#include <cstdlib>
template <class T1, class T2>
T1 lexical_cast(const T2& t2)
{
std::stringstream s;
s << t2;
T1 t1;
if(s >> std::noskipws >> t1 && s.eof()) {
// it worked, return result
return t1;
} else {
// It failed, do something else:
// maybe throw an exception:
throw std::runtime_error("bad conversion");
// maybe return zero:
return T1();
// maybe do something drastic:
exit(1);
}
}
int main() {
std::string smin, smax;
int imin, imax;
while(std::cout << "Enter min and max: " && std::cin >> smin >> smax) {
try {
imin = lexical_cast<int>(smin);
imax = lexical_cast<int>(smax);
break;
} catch(std::runtime_error&) {
std::cout << "Try again: ";
continue;
}
}
if(std::cin) {
std::cout << "Thanks!\n";
} else {
std::cout << "Sorry. Goodbye\n";
exit(1);
}
}
Related Topics
Getting Std :: Ifstream to Handle Lf, Cr, and Crlf
Why Must the Copy Assignment Operator Return a Reference/Const Reference
How to Sort Two Vectors in the Same Way, With Criteria That Uses Only One of the Vectors
Why Does Integer Overflow on X86 With Gcc Cause an Infinite Loop
How Does C++ Linking Work in Practice
How Can a Windows Service Execute a Gui Application
Variable Initialization in C++
Std::Endl Is of Unknown Type When Overloading Operator≪≪
Getting Size of Array from Pointer C++
What Open Source C++ Static Analysis Tools Are Available
How to Output Coloured Text to a Linux Terminal
How to Use a C++ String in a Structure When Malloc()-Ing the Same Structure