Problem with string conversion to number ( strtod )
Solution 1
The 2nd argument to the strtod
function is useful.
char *err;
d = strtod(userinput, &err);
if (*err == 0) { /* very probably ok */ }
if (!isspace((unsigned char)*err)) { /* error */ }
Edit: examples added
The strtod
function tries to convert the initial portion of the 1st argument to a double and stops either when there are no more chars, or there is a char that can't be used to make a double.
input result ---------- ---------------------------- "42foo" will return 42 and leave err pointing to the "foo" (*err == 'f') " 4.5" will return 4.5 and leave err pointing to the empty string (*err == 0) "42 " will return 42 and leave `err` pointing to the spaces (*err == ' ')
Solution 2
man strtod
: If no conversion is performed, zero is returned and the value of nptr is stored in the location referenced by endptr.
char * endptr;
double d = strtod(strEnv, &endptr);
if (strEnv == endptr)
/* invalid number */
else
...
Solution 3
Surely you could do worse than just reading the man page for strtod() and acting upon that. E.g. on my Linux system it says:
RETURN VALUE These functions return the converted value, if any. If endptr is not NULL, a pointer to the character after the last character used in the conversion is stored in the location referenced by endptr. If no conversion is performed, zero is returned and the value of nptr is stored in the location referenced by endptr. If the correct value would cause overflow, plus or minus HUGE_VAL (HUGE_VALF, HUGE_VALL) is returned (according to the sign of the value), and ERANGE is stored in errno. If the correct value would cause underflow, zero is returned and ERANGE is stored in errno.
That pretty much tells you what you need to do in order to handle errors. Also, like Johann Gerell said, you also need to check whether getenv() succeeded; a similar approach works there, i.e. check the man page and write error handling code according to that.
Solution 4
- First, check the return value of
getenv
- if it's NULL, then that environment variable doesn't exist. - Second, if the return value of
getenv
isn't NULL, then you have the value, as a string. - Third, don't set the
char ** endptr
parameter ofstrtod
to NULL, but use it to check the validity of the converted value, also check for0.0
.
RajSanpui
Around 9+ years experience into development C, C++, and Linux domain. Also understand Core-Java and consider it as a secondary skill. Currently, in addition to the developer responsibilities, i am also serving the role of DevOps engineer.
Updated on August 04, 2022Comments
-
RajSanpui over 1 year
I am using strtod( ) function to extract an environment variable as a string, and then changing it to double using strtod:
enter code here char strEnv[32]; strncpy(strEnv, getenv("LT_LEAK_START"), 31); // How to make sure before parsing that env LT_LEAK_START is indeed a number? double d = strtod(strEnv, NULL);
Now i want to make sure that this number entered by user is a number and not a string or special character. How can i make sure of that?
A code snippet would be of great help.
Thanks in advance.
-
RajSanpui about 13 years@pmg: Thanks a ton. But i am not exactly able to understand, what exactly you are trying to do with err?
-
RajSanpui about 13 years@pmg: So, separately, shall we check all for special characters, etc, isalpha, like that?
-
RajSanpui about 13 yearsYou haven't made any checks for special characters?
-
log0 about 13 years@kingsmasher1 if there is a special character. It is not a valid number anyway. So the conversion fails and endptr is set to strEnv.
-
RajSanpui about 13 years@pmg: Thanks a lot for the examples. Then why check for spaces? CAn't we directly check for
(*err==0)
? -
pmg about 13 yearsThe input
"4 2"
will return 4 and leavefoo
pointing to" 2"
. I think that is an invalid number, just checking for 1 space in *err is not enough. -
RajSanpui about 13 years@pmg: Thanks, your is the best explanation. Many others were also useful.
-
pmg about 13 yearsYour answer is misleading: there may be cases where
strEnv != endptr
and the number was valid, for example"42 "
(space at the end) -
log0 about 13 years@pgm in fact you always have
strEnv != endptr
if the number is valid. -
log0 about 13 years@pmg However I still don't agree with your answer. if you have
" foo",
*err != 0` andisspace((unsigned char)*err) == true
-
pmg about 13 years@Ugo: you are correct. My code above is incomplete. It doesn't correctly validate for " foo" or "" (empty string). It was only meant as an example usage of the 2nd argument to
strtod()
. -
Jonathan Wood over 4 yearsIt doesn't tell you all you need to know at all if you want to know if the string is valid. Returning 0.0 on error is fine unless of course 0.0 is a valid floating point value!
-
janneb over 4 years@JonathanWood: Sure it does; read the man page more carefully!
-
janneb over 4 years@JonathanWood: There are many aspects of C and the C standard library that can be considered flawed, but this function isn't particularly high on the list. As for your question, it's right there in the part I quoted: "If no conversion is performed, zero is returned and the value of nptr is stored in the location referenced by endptr."
-
janneb over 4 years@JonathanWood: As for what a "man page" is, the first search engine hit is en.wikipedia.org/wiki/Man_page , which explains it pretty well. (Also note the question is tagged "linux", so the fact that non-Unix systems might not have man pages isn't particularly relevant here).