Test if a string is a number In need for testing if a string is a number which could be a double or integer, I wrote a simple skeleton, which parses a string like this:

#include &lt;stdio.h&gt;
#include &lt;stdlib.h&gt;
#include &lt;string.h&gt;
#include &lt;errno.h&gt;

int main(int argc, char *argv[])
{

char* to_convert = argv[1];
char* p = NULL;
errno = 0;
long val = strtol(argv[1], &amp;p, 0);

if (errno != 0)
return 1;// conversion failed (EINVAL, ERANGE)

if (to_convert == p){
// conversion to int failed (no characters consumed)
double val2 = strtod(p, &amp;p);
if (*p){
printf("Not a number!\n");
return 1;
}
printf("Double %lf\n" , val2);
return 0;
}

if (*p != 0){
// conversion to int failed (trailing data)
double val2 = strtod(argv[1], &amp;p);
if (*p){
printf("Not a number!\n");
return 1;
}
printf("Double %lf\n" , val2);
return 0;
}

printf("Int %ld\n" , val);
return 0;
}

/*
$ ./a.out 123
Int 123
$ ./a.out -123
Int -123
$ ./a.out 31.1
Double 31.100000
$ ./a.out -231
Int -231
$ ./a.out NaN
Double nan
$ ./a.out -Nan
Double nan
$ ./a.out -INF
Double -inf
$ ./a.out INF
Double inf
$ ./a.out 12.3
Double 12.300000
$ ./a.out -12,3  # Although some european localels (like German, would consider this a number)
Not a number!
$ ./a.out -12.3
Double -12.300000
$ ./a.out foo
Not a number!
*/ 


I would like to know if this could be done better, without iterating on all the characters like here.  


Is there any case I didn't think of which breaks this code? 
or causes undefined behaviour (except numbers larger than long on my architechture)? 


Another thing is the problem with decimal seperator. How do you convert a number where the decimal separator is comma instead of a point like in the German language? This would be a nice to have, but not a must.

For example, my code says 12,3 is not a number, for a German person this would be a number (12.3 for English speakers).
int test and double test are incompletely done.

errno = 0;
long val = strtol(argv[1], &amp;p, 0);
if (errno) Fail();         // Range error (or possible other reasons)
if (argv[1] == p) Fail();  // no conversion
while (isspace((unsigned char) *p)) p++;
if (*p) Fail();            // Extra junk afterwards


if (*p) Fail(); Needs to be applied to both integer and FP test.

while (isspace((unsigned char) *p)) p++; allows trailing white-space.  Both strtol() and strtod() allow leading white-space.

Double is more complex as in the case of underflow like "1e-10000", the errno may set and that is usually not considered an error in many uses.  The returned value will be either +/-0.0 or a small double value.

double val2 = strtod(argv[1], &amp;p);
if (errno == ERANGE &amp;&amp; fabs(val2) &lt;= DBL_MIN) NoFail();


Keep in mind a string may nicely translate to a long as well as a double.  Should "-0" be along 0 or double -0.0?  Aside from this case, I would favor long, especially if the test for extra junk is used.

Your test cases do not include big values "123...thousand_more...456", values like LONG_MIN (-1, +0, +1) and  LONG_MAX (-1, +0, +1), DBL_MAX, next_after(DBL_MAX,0), strings with trailing garbage "123xyz", -0.0.  BTW: a harsh check it to use (char) -1 in various places in the string. Or lead the string with (char) (x80 + ' ')

Nor does it test odd things like "++123", "0x0xABC", "08".  (multiple sign, 2-prefix, octal 8) and new emerging "0b0101"  (C14?)

Extreme FP strings include "0.000...0001e320", "" and "  " (white-space only strings.)

FP also has a hexadecimal format, see scanf("%a")/printf("%a") for additional strings.

Original request was for "double or integer".  Code conveniently uses long, but what if int was meant or intmax_t?  Example additional test for int

long val = strtol(argv[1], &amp;p, 0);
if (val &lt; INT_MIN || val &gt; INT_MAX) RangeError();
int i = (int) val;
...


To cope with decimal separator as , or ., use setlocale() and that will adjust strtol() and strtod().  But that is a weak aspect of C.

Lastly, a given locale could have "additional subject sequences" that convert into numbers.