Reputation: 269
I am trying to ensure user input is a positive integer and have got my function to work no matter what the user tries to put in.
int getNumber()
{
string userInput;
int userNumber;
bool badInput = true;
cout<<"Enter a positive integer: ";
cin>>userInput;
while (badInput)
{
for (int i=0; i<userInput.length(); i++)
{
if (isdigit(userInput[i]))
{
badInput = false;
}
else
{
badInput = true;
cout<<"That wasn't a valid input, try again: ";
cin>>userInput;
break;
}
}
}
userNumber = atoi(userInput.c_str());
return userNumber;
}
Is there a cleaner way to do this or is this the best way? I tried various other methods such as using cin.bad etc but they always managed to miss some issue.
Upvotes: 0
Views: 1433
Reputation: 153909
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.
Upvotes: 1
Reputation: 74018
You can use std::string::find_first_not_of()
for testing against digits and std::stoi
for overflow
std::string input;
bool badInput;
int i;
std::cout << "Enter a positive integer: ";
do {
std::cin >> input;
try {
badInput = input.find_first_not_of("0123456789") != std::string::npos;
if (!badInput)
i = std::stoi(input);
} catch (const std::invalid_argument&) {
badInput = true;
} catch (const std::out_of_range&) {
badInput = true;
}
if (badInput)
std::cout << "That wasn't a valid input, try again: ";
} while (badInput);
This doesn't check for a leading +
, though.
Upvotes: 0
Reputation:
Like mvp said, strol
is the way to go.
bool string_to_int(char* s, int* val) {
char* endptr;
errno = 0; /* reset errno */
int i = strtol(s, &endptr, 10);
if (endptr == s) return false; /* conversion failed */
if (*endptr) return false; /* unexpected characters behind the integer */
if (errno) return false; /* out of range */
*val = i;
return true;
}
Upvotes: 0