Using only ANSI C, what is the best way to, with fair certainty, determine if a C style string is either a integer or a real number (i.e float/double)?
9 Answers
Don't use atoi and atof as these functions return 0 on failure. Last time I checked 0 is a valid integer and float, therefore no use for determining type.
use the strto{l,ul,ull,ll,d} functions, as these set errno on failure, and also report where the converted data ended.
strtoul: http://www.opengroup.org/onlinepubs/007908799/xsh/strtoul.html
this example assumes that the string contains a single value to be converted.
#include <errno.h>
char* to_convert = "some string";
char* p = to_convert;
errno = 0;
unsigned long val = strtoul(to_convert, &p, 10);
if (errno != 0)
// conversion failed (EINVAL, ERANGE)
if (to_convert == p)
// conversion failed (no characters consumed)
if (*p != 0)
// conversion failed (trailing data)
Thanks to Jonathan Leffler for pointing out that I forgot to set errno to 0 first.

- 760
- 5
- 13
-
sorry, I knew that this is quite old, but in this line, we do not have any errno? unsigned long val = strtoul(to_convert, &p, 10); Is the correct would be unsigned long errno = strtoul(to_convert, &p, 10); – vodkhang Apr 27 '10 at 16:55
-
@vodkhang This is valid code, but you may have to use #include
depending on your compiler. errno is essentially a global variable that can be set with an error code. It may be implemented as a macro or a "modifiable lvalue". – Ben Gartner Jun 20 '10 at 05:24 -
`errno` **is** a macro which expands to a modifiable lvalue. Normally it expands to `(*__errno_location())` or similar. – R.. GitHub STOP HELPING ICE Dec 23 '10 at 23:34
-
to save anybody headaches, you may have to add #include
for it to work. – Dave Appleton Jul 01 '13 at 06:13
Using sscanf, you can be certain if the string is a float or int or whatever without having to special case 0, as is the case with atoi and atof solution.
Here's some example code:
int i;
float f;
if(sscanf(str, "%d", &i) != 0) //It's an int.
...
if(sscanf(str "%f", &f) != 0) //It's a float.
...

- 90,362
- 11
- 51
- 61
-
1I'm pretty sure you need to test the return value of sscanf against the sizeof str to make sure the whole string was converted, otherwise the "%d" won't fail if it's handed "1.374", it will return 1. – Patrick_O Sep 17 '08 at 00:59
-
True. This could also be solved by testing for %f first, but that causes issues with "1.". Personally, I like your solution the best of those presented. – Patrick Sep 17 '08 at 01:44
-
@Patrick_O Checking the return of `sscanf` against a string length is not going to work, since it returns the number of succesfully converted items, not the number of characters used for conversion. but the `%n` format may help here. – Jens Sep 03 '13 at 06:42
I agree with Patrick_O that the strto{l,ul,ull,ll,d} functions are the best way to go. There are a couple of points to watch though.
- Set errno to zero before calling the functions; no function does that for you.
- The Open Group page linked to (which I went to before noticing that Patrick had linked to it too) points out that errno may not be set. It is set to ERANGE if the value is out of range; it may be set (but equally, may not be set) to EINVAL if the argument is invalid.
Depending on the job at hand, I'll sometimes arrange to skip over trailing white space from the end of conversion pointer returned, and then complain (reject) if the last character is not the terminating null '\0'. Or I can be sloppy and let garbage appear at the end, or I can accept optional multipliers like 'K', 'M', 'G', 'T' for kilobytes, megabytes, gigabytes, terabytes, ... or any other requirement based on the context.

- 730,956
- 141
- 904
- 1,278
I suppose you could step through the string and check if there are any .
characters in it. That's just the first thing that popped into my head though, so I'm sure there are other (better) ways to be more certain.

- 112
- 2
Use strtol/strtoll (not atoi) to check integers. Use strtof/strtod (not atof) to check doubles.
atoi and atof convert the initial part of the string, but don't tell you whether or not they used all of the string. strtol/strtod tell you whether there was extra junk after the characters converted.
So in both cases, remember to pass in a non-null TAIL parameter, and check that it points to the end of the string (that is, **TAIL == 0). Also check the return value for underflow and overflow (see the man pages or ANSI standard for details).
Note also that strod/strtol skip initial whitespace, so if you want to treat strings with initial whitespace as ill-formatted, you also need to check the first character.

- 273,490
- 39
- 460
- 699
It really depends on why you are asking in the first place.
If you just want to parse a number and don't know if it is a float or an integer, then just parse a float, it will correctly parse an integer as well.
If you actually want to know the type, maybe for triage, then you should really consider testing the types in the order that you consider the most relevant. Like try to parse an integer and if you can't, then try to parse a float. (The other way around will just produce a little more floats...)

- 35,564
- 14
- 82
- 119
atoi and atof will convert the number even if there are trailing non numerical characters. However, if you use strtol and strtod it will not only skip leading white space and an optional sign, but leave you with a pointer to the first character not in the number. Then you can check that the rest is whitespace.
Well, if you don't feel like using a new function like strtoul, you could just add another strcmp statement to see if the string is 0.
i.e.
if(atof(token) != NULL || strcmp(token, "0") == 0)
-
This thinks that "0.0" (and other variations thereof) are not numbers. – Michael Feb 24 '16 at 17:44