how to check if given c++ string or char* contains only digits?

Of course, there are many ways to test a string for only numeric characters. Two possible methods are:

bool is_digits(const std::string &str)
{
    return str.find_first_not_of("0123456789") == std::string::npos;
}

or

bool is_digits(const std::string &str)
{
    return std::all_of(str.begin(), str.end(), ::isdigit); // C++11
}

Several people already mentioned to use isdigit(). However, note that this isn't entirely trivial because char can be signed which would cause a negative value to be passed to isdigit(). However, this function can only take positive values. That is, you want something akin to this:

if (s.end() == std::find_if(s.begin(), s.end(),
    [](unsigned char c)->bool { return !isdigit(c); })) {
    std::cout << "string '" << s << "' contains only digits\n";
}

It seems the reasoning for the conversion to unsigned char isn't obvious. So, here are the relevant quotes from their respective standards:

According to ISO/IEC 9899:2011 (or ISO/IEC 9899:1999) 7.4 paragraph 1 the following applies to the arguments of the functions from <ctype.h>:

... In all cases the argument is an int, the value of which shall be representable as an unsigned char or shall equal the value of the macro EOF. If the argument has any other value, the behavior is undefined.

Unfortunately, the C++ standard doesn't specify that char is an unsigned type. Instead it specifies in ISO/IEC 14882:2011 3.9.1 [basic.fundamental] paragraph 1:

... It is implementation-defined whether a char object can hold negative values. ...

Clearly, a negative value cannot be represented as an unsigned char. That is, if char is using a signed type on an implementation (there are actually several which do, e.g., it is signed on MacOS using gcc or clang) there is the danger that calling any of the <ctype.h> function would cause undefined behavior.

Now, why does the conversion to unsigned char does the right things?

According to 4.7 [conv.integral] paragraph 2:

If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type). [ Note: In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). —end note ]

That is, the conversion from a [potentially] signed char to unsigned char is well-defined and causes the result to be in the permitted range for the <ctype.h> functions.


isdigit(int) tells you if a character is a digit. If you are going to assume ASCII and base 10, you can also use:

int first_non_digit_offset= strspn(string, "0123456789")

In the same spirit as Misha's answer, but more correct: sscanf(buf, "%*u%*c")==1.

scanf returns 0 if the %d digit extraction fails, and 2 if there is anything after the digits captured by %c. And since * prevents the value from being stored, you can't even get an overflow.


The cctype header file has a good number of character classifications functions which you can use on each character in the string. For numeric checks, that would be isdigit.

The following program shows how to check each character of a C or C++ string ( the process is pretty much identical in terms of checking the actual characters, the only real difference being how to get the length):

#include <iostream>
#include <cstring>
#include <cctype>
int main (void) {
    const char *xyzzy = "42x";
    std::cout << xyzzy << '\n';
    for (int i = 0; i < std::strlen (xyzzy); i++) {
        if (! std::isdigit (xyzzy[i])) {
            std::cout << xyzzy[i] << " is not numeric.\n";
        }
    }

    std::string plugh ("3141y59");
    std::cout << plugh << '\n';
    for (int i = 0; i < plugh.length(); i++) {
        if (! std::isdigit (plugh[i])) {
            std::cout << plugh[i] << " is not numeric.\n";
        }
    }

    return 0;
}