# Checking if input is a string or an integer

I'm teaching myself C++ by reading Stroupstrup's Programming Principles and Practice Using C++, and I'm working on an exercise in chapter 4. The exercise asks to convert input as a digit to the corresponding spelled-out value e.g. input of 1 gives the output "one".

#include "std_lib_facilities.h"

using namespace std;

//Workaround for compiler issue.
int stoi( const std::string& str, std::size_t* pos = 0, int base = 10 )
{
const char* begin = str.c_str() ;
char* end = nullptr ;
long value = std::strtol( begin, &end, base ) ;

if( errno == ERANGE || value > std::numeric_limits<int>::max() )
throw std::out_of_range( "stoi: out ofrange" ) ;

if( end == str.c_str() )
throw std::invalid_argument( "stoi: invalid argument" ) ;

if(pos) *pos = end - begin ;

return value ;
}

int main()
{
struct Numbers
{
string spelled;
int digit;
};
const Numbers nums[]
{
{"zero", 0},
{"one", 1},
{"two", 2},
{"three", 3},
{"four", 4},
{"five", 5},
{"six", 6},
{"seven", 7},
{"eight", 8},
{"nine", 9},
{"ten", 10}
};

string response = " ";

cout << "Type a number either spelled out or as a digit.\n";

cin >> response;
if(response.size() == 1)
{
cout << nums[stoi(response)].spelled;
}
else if(response.size() > 1)
{
for(int i=0; i<=10; ++i)
{
if(response == nums[i].spelled)
{
cout << nums[i].digit << endl;
break;
}
else;
}
}
}


Is there a better way to check the type of input the user gives other than checking the response size? Would it have been easier/more efficient if I had used a vector? In my for loop, does that break in the if statement break the loop?

• Sorry if I'm missing something, but does your code handle multi-digit numbers? (like 25?) Somehow reading through this quickly, I am missing a case where you'd handle multiple digit numbers. – sunny Sep 23 '15 at 14:29

This is now a conflict:

using namespace std;

//Workaround for compiler issue.
int stoi( const std::string& str, std::size_t* pos = 0, int base = 10 )


There is an stoi in the standard namespace. Because you used using this will be considered with your function. They both have the same parameter types so this should generate a compiler error.

The only reason it may not be doing so is that you are using an archaic version of the language.

You have to reset errno to a zero state before using a function that sets it (std::strtol does not change the value if there is no error it just sets the value if there is an error).

    if( errno == ERANGE || value > std::numeric_limits<int>::max() )
throw std::out_of_range( "stoi: out ofrange" ) ;


This will fail if a previous library call set errno to ERANGE.

Don't like the extra indention of you r function:

int stoi( const std::string& str, std::size_t* pos = 0, int base = 10 )
{
^^^^!


Prefer to use {} around block statements.

if( errno == ERANGE || value > std::numeric_limits<int>::max() )
throw std::out_of_range( "stoi: out ofrange" ) ;

// Best to be safe
// So consistent use of '{}' is usually best.
if( errno == ERANGE || value > std::numeric_limits<int>::max() ) {
throw std::out_of_range( "stoi: out ofrange" ) ;
}


Readability enhanced by using another line:

if(pos) *pos = end - begin ;

// Easier to read for your next maintainer.
if(pos) {
*pos = end - begin ;
}

• The workaround is solely for me. Codeblocks, for whatever reason, does not recognize stoi for me even though I'm using C++11. That said, you didn't answer any of my question. – CoopTang Sep 27 '15 at 22:37