Checking for legitimate integer input in c++ - c++

so i've seen many people ask this and not many solid answers floating around the web. most just check that an integer was placed in place of a string but if a floating point number was entered then it truncates the bottom half or if integers and characters are intered it truncates the characters. i need help writing a piece of code that checks for user input and asks the user to retry if his input is not valid or a combination of valid/invalid. i think the basic idea was to make a string so it accepts anything then use sstream to manipulate and then back to int if the input was legit but i cant really manage to check the other parts. if anyones run accross this or can help me out please link me to it. i'll post my code when i get a good sense of what to do.

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

You can use C++11 string conversion functions like stol
try
{
std::string value = ...;
long number = std::stol(value);
}
catch (std::invalid_argument const& e)
{
// no conversion could be performed
}
Post-comments update: Visual C++ 11 shipped with Visual Studio 2012 implements std::stol as a convenient wrapper around strtol declared in <cstdlib>. I think it's safe to assume most C++11 implementations define it in most optimal way possible, not reaching for std::stringstream machinery.

The C function strtol (and it's siblings) will be able to tell you if the string fed to it is completely consumed.
std::string str;
char *endptr;
std::cin >> str;
long x = std::strtol(str.c_str(), &endptr, 0);
if (*endptr != 0)
cout << "That's not a valid number...";

I don't know if there are any classes in standard c++ lib that encapsule primitive types like in java but here how a simple and very basic implementation would look like
class Integer {
private:
int value;
void parse(string);
public:
Integer(string);
int intValue();
};
Integer::Integer(string sint) { parse(sint); }
int Integer::intValue() { return value; }
void Integer::parse(string sint) {
string::iterator its = sint.begin();
while(its != sint.end() && (! (*its < '0' || *its > '9'))) {
its++;
}
if(its != sint.end()) {
throw sint + ": Input is not a valid integer.";
}
value = atoi(sint.c_str());
}

Related

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 check if the input taken by the user doesn't contain decimal?

I am a newbie to C++. I have a situation where the input integer is taken from the user. However, I need to check if the user enters a decimal value. How do I check this?
I have tried cin.good(), cin.fail() but they are detecting only non-digit entries and not decimal numbers. Any help would be appreciated.
#include <iostream>
int main()
{
using namespace std;
int x;
cout << "Enter an integer: " << endl;
cin >> x;
if (cin.good()) {
cout << "input is an integer" << endl;
}
else
cout << "input is not an integer" << endl;
}
Here's my output:
1.
Enter an integer:
1.2
input is an integer
2.
Enter an integer:
a
input is not an integer
float x = 4.2;
if (x == (int) x)
{
// int
}
else
{
// not int
}
You can use std::isdigit for checking your string input next way.
bool is_numeric(const std::string& str)
{
std::string::const_iterator it = str.begin();
if (it != str.end() && *it == '-') ++it;
if (it == str.end()) return false;
while (it != str.end() && std::isdigit(*it)) ++it;
return it == str.end();
}
It's not hard to change it to work with floating points, if needs, but that function will exactly checks what you need.
You receive the input as an int from cin and hence any float entered would already be truncated by the time you get your hands on it. You should receive it as a float or a string to decide on the validity of the input.
Removed the earlier answer since it went down the slippery route of manually parsing the input which is unnecessary and error-prone. The standard library already has multiple ways to check if an input is a valid number. Two ways that I know: C++ streams and the C library function strtof. Here's an example using the latter:
#include <iostream>
#include <string>
#include <cmath>
bool is_int(float f) {
return std::floor(f) == f;
}
int main()
{
std::cout << "Enter an integer: ";
std::string input;
std::cin >> input;
char *e = nullptr;
char const *str = input.c_str();
float const f = strtof(str, &e);
// no conversion was performed or was stopped as disallowed
// characters were encountered: Not A Number
if ((e == str) || (*e != '\0'))
std::cout << "NAN";
else if ((f == HUGE_VALF) || !std::isfinite(f))
std::cout << "too large";
else
std::cout << (is_int(f) ? "integer" : "non-integer");
std::cout << '\n';
}
Live example.
To check if the input is a number, this
float f;
cin >> f;
is possible too, but it will also accept NANs as valid input e.g. 45dsf will be converted to 45. One has to then check if the conversion happened completely and successfully by checking the fail and eof bits of the stream.
See also
Checking if float is an integer
C++ IsFloat function
How to convert a number to string and vice versa in C++

Distinguishing between an int and a double

I've searched for this answer, and no one seems to know how to fix this error. I want the input to be strictly an int. If the input is a double, I want it to send an error.
int creatLegs = 0;
string trash;
bool validLegs = true;
do
{
cout << "How many legs should the creature have? ";
cin >> creatLegs;
if(cin.fail())
{
cin.clear();
cin >> trash; //sets to string, so that cin.ignore() ignores the whole string.
cin.ignore(); //only ignores one character
validLegs = false;
}
if (creatLegs > 0)
{
validLegs = true;
}
if (!validLegs)
{
cout << "Invalid value, try again.\n";
}
} while (!validLegs);
It seems to almost work. It sends the error, but only after moving onto the next loop. How can I fix this? And why is it still showing the error message but still moving on before showing it?
An input can be something else than a representation of an integer or of a floating point number.
Remember that numbers are not their representation(s): 9 (decimal), 017 (octal, à la C), 0b1001 (binary, à la Ocaml), IX (Roman notation), 8+1 (arithmetic expression), neuf (French) are all representations of the same number nine.
So you have to decide if you accept an input like 9 x, or 9 (with several spaces after the digit), ... More generally you have to define what are the acceptable inputs (and if the input is ending at end of line or not, if spaces or punctuation should be accepted, etc...).
You could read an entire line (e.g. with std::getline) and use e.g. sscanf (where the %n control format is useful, and so is the item count returned by sscanf) or std::stol (where you use the end pointer) to parse it
Notice also that the phrasing of your question ("Distinguishing between an int and a double") is wrong. There is no single "int or double" type in C++ (but int is a scalar type, and double is a scalar type in C++, and you could define a class with a tagged union to hold either of them). AFAIU, if you declare int x; then use std::cin >> x; with the user inputting 12.64 the dot and the digits 64 after it won't be parsed and x would become 12.
I think that you should read data as string, and then check it char by char to verify that it is integer - if every char is a digit, then we have integer and we can parse it.
Problem with streams is, that if you're trying to read integer but decimal is passed, it reads the number up to the dot. And this part is a proper integer, so cin.fail() returns false.
Sample code:
#include <iostream>
#include <string>
#include <cctype>
#include <cstdlib>
using namespace std;
int main() {
int creatLegs = 0;
bool validLegs = true;
do
{
cout << "How many legs should the creature have? ";
string input;
getline(cin, input);
validLegs = true;
for (string::const_iterator i = input.begin(); validLegs && i != input.end(); ++i) {
if (!isdigit(*i)) {
validLegs = false;
}
}
if (!validLegs)
{
cout << "Invalid value, try again.\n";
} else {
creatLegs = atoi(input.c_str());
}
} while (!validLegs);
cout << creatLegs << endl;
}
This of course is not a perfect solution. If there any leading or trailing spaces (or any other characters like + or -), the program will fail. But you always can add some code to handle those situations, if you need to.
int creatLegs = 0;
do
{
cout << "How many legs should the creature have? ";
cin >> creatLegs; // trying to get integer
if(!cin.fail()) // if cin.fail == false, then we got an int and leave loop
break;
cout << "Invalid value, try again.\n"; // else show err msg and try once more
cin.clear();
} while (1);
This question already has an accepted answer, however I'll contribute a solution that handles all numbers that are integral, even those that are expressed as a floating point number (with no fractional part) and rejects input that contains anything other than spaces following the number.
Examples of accepted values, these all represent the number 4:
4
4.
4.0
+4
004.0
400e-2
Examples of rejected values:
3.999999
4.000001
40e-1x
4,
#include <iostream>
#include <sstream>
#include <cctype>
#include <string>
using namespace std;
bool get_int( const string & input, int & i ) {
stringstream ss(input);
double d;
bool isValid = ss >> d;
if (isValid) {
char c;
while( isValid && ss >> c ) isValid = isspace(c);
if (isValid) {
i = static_cast<int>(d);
isValid = (d == static_cast<double>(i));
}
}
return isValid;
}
int main( int argc, char *argv[] )
{
int creatLegs = 0;
bool validLegs = false;
do
{
string line;
do {
cout << "How many legs should the creature have? ";
} while (not getline (cin,line));
validLegs = get_int( line, creatLegs );
if (creatLegs <= 0)
{
validLegs = false;
}
if (not validLegs)
{
cout << "Invalid value, try again." << endl;
}
} while (not validLegs);
cout << "Got legs! (" << creatLegs << ")" << endl;
return 0;
}
If you want strictly integers (no decimal period and no scientific notation) then use this simpler get_int function:
bool get_int( const string & input, int & i ) {
stringstream ss(input);
bool isValid = ss >> i;
if (isValid) {
char c;
while(isValid && ss >> c) isValid = isspace(c);
}
return isValid;
}

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

Is this the correct approach to do input validation with floating point values?

After spending a good amount of time researching input validation, I combined a few ideas and came up with this:
Function to check a string for a valid double...
bool isDouble(double& destination, string& source)
{ // 64 bit
bool goodValue = false;
if (!source.empty()) {
errno = 0;
char *garbage = nullptr;
destination = strtod(source.c_str(), &garbage);
if (*garbage == '\0' && errno != ERANGE)
goodValue = true;
}
return goodValue;
}
Function to check a string for a valid 32 bit integer...
bool isLong(long& destination, string& source)
{ // 32 bit (base 10)
const short BASE = 10;
bool goodValue = false;
if (!source.empty()) {
errno = 0;
char* garbage = nullptr;
destination = strtol(source.c_str(), &garbage, BASE);
if (*garbage == '\0' && errno != ERANGE)
goodValue = true;
}
return goodValue;
}
Sample Implementation
using namespace std;
int main() {
string buffer;
double value;
cout << "Enter a value: ";
getline(cin, buffer, '\n');
if (isDouble(value, buffer))
cout << "Value: " << value << endl;
else
cout << "ERROR: Invalid input\n";
return 0;
}
Can anyone comment on if I am overlooking anything with this approach?
I'm not sure about "the" correct way, but it's certainly not how I'd do it. First and probably most obvious, this chunk of code:
for (i = 0, d = 0; i < BUFFSIZE && buffer[i] != 0 && buffer[i] >= '0' &&
buffer[i] <= '9' || (buffer[i] == '.' && d == 0); i++)
if (buffer[i] == '.') ++d;
is duplicated in a couple of places (at least I think the other instance is identical, and probably should be anyway).
Second, you don't appear to allow numbers like 1e23 or -1.2, which are usually accepted as floating point.
Offhand, I think I'd use strtod to attempt to convert the input. You can use its second parameter to detect whether a conversion reached the end of the input string (if not, you'll know at least part of the input wasn't accepted). You'll then (apparently) want to check that the returned value was in the desired range.
Perhaps the strtod() function can be of help here, as it tells you how much has been converted:
const char * buf = get_raw_data(); // somehow
char * endptr;
const double value = strtod(buf, &endptr);
if (endptr != buf + std::strlen(buf)) { /* ... error ... */ }
As the source for buf you could tokenize your input with std::string token; std::cin >> token; or something like that and use token.c_str().
If it's an exercise you want, that's understandable. But otherwise, you can use istringstream to avoid reinventing the wheel:
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
int main () {
int n,val;
string stringvalues;
stringvalues = "3.14159254 f01fhasfljk";
istringstream iss(stringvalues);
float x,y;
iss >> x;
cout << x * 2 << endl;
iss >> y;
if ( ! iss.fail() )
{
cout << y * 2 << endl;
}
else
{
cout << "second value not a number..." << endl;
}
return 0;
}