8

I wrote the following code to check whether the input(answer3) is a number or string, if it is not a number it should return "Enter Numbers Only" but it returns the same even for numbers. Please suggest me a solution.

#include <iostream>
#include <string>
#include <typeinfo>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

using namespace std; 
int main ()
{

string ques1= "Client's Name :";
string ques2 = "Client's Address :";
string ques3 = "Mobile Number :";

char answer1 [80];
string answer2;
int answer3;

     cout<<ques1<<endl;    
     cin>>answer1;      

     cout<<ques2<<endl;    
     cin>>answer2; 

     cout<<ques3<<endl;
     cin>>answer3;

       if (isdigit(answer3))
       {
              cout<<"Correct"<<endl;     

              }

        else
        {
          cout<<"Enter Numbers Only"<<endl;  

            }

 system("pause>null");
 return 0;  

}
John Snow
  • 1,898
  • 2
  • 27
  • 48
Rukshan Mahendra
  • 113
  • 1
  • 1
  • 7
  • 8
    Is there something wrong with the enter key on your keyboard? The spacebar seems dodgy as well – Ed Heal Feb 16 '14 at 05:25
  • 1
    `isdigit` takes a single character as an `int`, interprets it as an ASCII character, and returns nonzero if it's a digit character ('0' through '9', ASCII 48 through 57) or zero if it's not. It has no way to tell you if you read an integer into `answer3`. – Mike DeSimone Feb 16 '14 at 05:33
  • 1
    Further, `cin >> someIntVariable` discards leading whitespace, reads an optional sign (`-` or `+`) followed by a sequence of digits, stopping at the first non-digit character. So if someone enters something that can't be interpreted, it sets the variable to 0. Which is why `isdigit` later fails. – Mike DeSimone Feb 16 '14 at 05:42
  • It makes no sense to call `isdigit` on an `integer` unless you know *precisely* what it means for an integer to *be* a digit. – David Schwartz Feb 16 '14 at 06:02

7 Answers7

9

You can use regex to do this:

#include <regex>

bool isNumber(std::string x){
    std::regex e ("^-?\\d+");
    if (std::regex_match (x,e)) return true;
    else return false;}

If you want to make isNumber() a generic function which can take any type of input:

#include <regex>
#include <sstream>

template<typename T>
bool isNumber(T x){
    std::string s;
    std::regex e ("^-?\\d+");
    std::stringstream ss; 
    ss << x;
    ss >>s;
    if (std::regex_match (s,e)) return true;
    else return false;}

The above isNumber() function checks for integer only, double or float value with precision (which contains dot .) will not return true. If you want precision too, then change the regex line to:

std::regex e ("^-?\\d*\\.?\\d+");

If you want a more efficient solution, see this one.

Community
  • 1
  • 1
Jahid
  • 21,542
  • 10
  • 90
  • 108
7

If you're using C++98, you can use stringstreams (#include <sstream>):

std::string s = "1234798797";
std::istringstream iss(s);

int num = 0;

if (!(iss >> num).fail()) {
    std::cout << num << std::endl;
}
else {
    std::cerr << "There was a problem converting the string to an integer!" << std::endl;
}

If boost is available to you, you can use lexical_cast (#include <boost/lexical_cast.hpp>):

std::string s = "1234798797";
int num = boost::lexical_cast<int>(si);//num is 1234798797
std::cout << num << std::endl;

If C++11 is available to you, you can use the builtin std::stoi function from <string>:

std::string s = "1234798797";
int mynum = std::stoi(s);
std::cout << mynum << std::endl;

OUTPUTS:

1234798797
jrd1
  • 10,358
  • 4
  • 34
  • 51
3

The function isdigit() is used to test for only digits ( 0,1,...,9)

use this function to check for numbers

bool is_number(const std::string& s)
{
    std::string::const_iterator it = s.begin();
    while (it != s.end() && std::isdigit(*it)) ++it;
    return !s.empty() && it == s.end();
}
Chethan N
  • 1,110
  • 1
  • 9
  • 23
2

The input to isdigit is an integer value. However, it will return true (non-zero) only if the value corresponds to '0'-'9'. If you convert them to integer values, they are 48-57. For all other values, isdigit will return false (zero).

You can check whether you got an integer by changing checking logic:

if ( cin.fail() )
{
   cout<<"Correct"<<endl;     
}
else
{
   cout<<"Enter Numbers Only"<<endl;  
}
R Sahu
  • 204,454
  • 14
  • 159
  • 270
1

Another answer using strtod:

bool isNumber(const std::string& s){
   if(s.empty() || std::isspace(s[0]) || std::isalpha(s[0])) return false ;
   char * p ;
   strtod(s.c_str(), &p) ;
   return (*p == 0) ;
}

To be able to handle any type of parameter use template:

#include <sstream>

template<typename T>
bool isNumber(T x){
   std::string s;
   std::stringstream ss; 
   ss << x;
   ss >>s;
   if(s.empty() || std::isspace(s[0]) || std::isalpha(s[0])) return false ;
   char * p ;
   strtod(s.c_str(), &p) ;
   return (*p == 0) ;
}

Note:

  1. White space will make it return false.
  2. NAN and INF will make it return false (to be exact, any character except valid exponent will make it return false). If you want to allow nan and inf, delete the || std::isalpha(s[0]) part.
  3. scientific form is allowed i.e 1e+12 will return true.
  4. Double/float or integer will return true.
  5. This is more efficient than the regex answer. (regex is heavy).
Community
  • 1
  • 1
Jahid
  • 21,542
  • 10
  • 90
  • 108
0

The interest phenomenon are the isdigit requires char to be cast to unsigned char. (Also see here).

Community
  • 1
  • 1
user3277268
  • 165
  • 3
0

This is a somewhat old question, but I figured I'd add my own solution that I'm using in my code.

Another way to check if a string is a number is the std::stod function, which has been mentioned, but I use it a bit differently. In my use case, I use a try-catch block to check if the input is a string or number, like so with your code:

...
try {
    double n = stod(answer3);
    //This will only be reached if the number was converted properly.
    cout << "Correct" << endl;
} catch (invalid_argument &ex) {
    cout << "Enter Numbers Only" << endl;
}
...

The primary problem with this solution is that strings that begin with numbers (but aren't all numbers) will be converted to numbers. This can be easily fixed by using std::to_string on the returned number and comparing it to the original string.

MarkSill
  • 73
  • 1
  • 8