How can we check if an input string is a valid double? - c

If I'm reading numbers of type double from stdin, how can I check if the numbers being read are in fact valid (that the numbers are in fact a double)?

You can use strtod. Check if the result is zero and subsequently if endptr == nptr, according to the man page:
If no conversion is performed, zero is returned and the value of nptr is stored in the location referenced by endptr.
Something like this:
char input[50];
char * end;
double result = 0;
fgets(input, sizeof input, stdin);
errno = 0;
result = strtod(input, &end);
if(result == 0 && (errno != 0 || end == input)){
fprintf(stderr, "Error: input is not a valid double\n");
exit(EXIT_FAILURE);
}
EDIT there seems to be a bit of a discrepancy between the standard and the man page. The man page says that endptr == nptr when no conversion is performed, while the standard seems to imply this isn't necessarily the case. Worse still it says that in case of no conversion errno may be set to EINVAL. Edited the example code to check errno as well.
Alternatively, sscanf could be used (preferred over scanf), in conjunction with fgets:
/* just fgetsed input */
if(sscanf(input, "%lf", &result) != 1){
fprintf(stderr, "Error: input is not a valid double\n");
exit(EXIT_FAILURE);
}
Also, don't forget to check the return value of fgets for NULL, in case it failed!

Neither simple strtod nor sscanf are enough to distinguish cases such as 1,5 or 1blah from desired 1.0 - All of these will result in 1.0. The reason is that
The strtod(), strtof(), and strtold() functions convert the initial portion of the string pointed to by nptr to double, float, and long double representation, respectively.
To ensure that the entire string was a valid double literal, use strtod like this:
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
...
char *endptr;
errno = 0;
double result = strtod(input, &endptr);
if (errno != 0 || *endptr != '\0') {
fprintf(stderr, "the value could not be represented as a double exactly\n");
}
The errno will be set if the value cannot be represented (ERANGE). Additionally, end will be pointing to the first character not converted. If the locale has not been set, when parsing 1,5 or 1blah, endptr will point to the second character. Iff the entire string was successfully parsed as a double constant, *endptr will point to the terminating '\0'.
Note that the errno must be set to zero prior to calling the function, otherwise it will retain the value from a previous failed function call.

How can we check if an input string is a valid double?
Start with
strtod() for double,
strtof() for float and
strtold() for long double.
double strtod(const char * restrict nptr, char ** restrict endptr);
The strtod, ... functions convert the initial portion of the string pointed to by nptr to double ....
A pointer to the final string is stored in the object pointed to by endptr, provided that endptr is not a null pointer.
C11dr §7.22.1.3 2&5
Simplified code to check loosely for validity. Does not complain about over/underflow nor extra text.
// Return true on valid
bool valid_string_to_double(const char *s) {
char *end;
strtod(s, &end);
return s != end;
}
Challenges of using strto*() include: errno == RANGE on arithmetic overflow and maybe underflow. The return value on overflow is only specified in default rounding mode. That value is HUGE_VAL which may be an infinity or a great number. The return value on underflow is implementation defined. errno has been known to be set to other non-zero values on conditions not specified by the C spec. Leading white-space is allowed, trailing white-space is not considered.
Sample function that looks for 1) conversion, 2) extra space, 3) over/underflow. It not only returns a valid indication, it also addresses the value of the conversion and the state of errno afterward.
// Return 0 on success
// Return non-0 on error, adjust these values as needed - maybe as an `enum`?
int convert_string_to_double(double *y, const char *s) {
char *end;
errno = 0;
*y = strtod(s, &end);
if (s == end) {
return 1; // Failed: No conversion, *y will be 0
}
// This may/may not constitute an error - adjust per coding goals
// Too great or too small (yet not exactly 0.0)
if (errno == ERANGE) {
if (fabs(*y) > 1.0) {
return 2; // Overflow
}
// In the case of too small, errno _may_ be set. See §7.22.1.3 10.
// For high consistency, return 0.0 and/or clear errno and/or return success.
// *y = 0.0; errno = 0;
}
// What to do if the remainder of the string is not \0?
// Since leading whitespace is allowed,
// let code be generous and tolerate trailing whitespace too.
while (isspace((unsigned char) *end)) {
end++;
}
if (*end) {
return 3; // Failed: Extra non-white-space junk at the end.
}
return 0; // success
}
If the result underflows (7.12.1), the functions return a value whose magnitude is no greater than the smallest normalized positive number in the return type; whether errno acquires the value ERANGE is implementation-defined. C11dr §7.22.1.3 10
A consideration includes the value of errno after this function is done. The C spec only species errno == ERANGE for strtod(), yet various implementations have been known to set errno to other values for other reasons including "no conversion". Code could clear errno except when ERANGE for high consistency.

You could use the standard atof function. It returns 0 on fail - and you could test if the string was 0 beforehand.
http://www.cplusplus.com/reference/cstdlib/atof/

Related

How to check if input is numeric(float) or it is some character?

I was asked to write a program to find sum of two inputs in my college so I should first check whether the input is valid.
For example, if I input 2534.11s35 the program should detect that it is not a valid input for this program because of s in the input.
to check input is numeric(float)
1) Take input as a string char buf[Big_Enough]. I'd expect 160 digits will handle all but the most arcane "float" strings1.
#define N 160
char buf[N];
if (fgets, buf, sizeof buf, stdin) {
2) Apply float strtof() for float, (strtod() for double, strtold() for long double).
char *endptr;
errno = 0;
float d = strtof(buf, &endptr);
// endptr now points to the end of the conversion, if any.
3) Check results.
if (buf == endptr) return "No_Conversion";
// Recommend to tolerate trailing white-space.
// as leading white-spaces are already allowed by `strtof()`
while (isspace((unsigned char)*endptr) {
endptr++;
}
if (*endptr) return "TrailingJunkFound";
return "Success";
4) Tests for extremes, if desired.
At this point, the input is numeric. The question remains if the "finite string" an be well represented by a finite float: if a the |result| is in range of 0 or [FLT_TRUE_MIN...FLT_MAX].
This involves looking at errno.
The conversion "succeed" yet finite string values outside the float range become HUGE_VALF which may be infinity or FLT_MAX.
Wee |values| close to 0.0, but not 0.0 become something in the range [0.0 ... INT_MIN].
Since the goal is to detect is a conversion succeeded (it did), I'll leave these details for a question that wants to get into the gory bits of what value.
An alternative is to use fscanf() to directly read and convert, yet the error handling there has its troubles too and hard to portably control.
1 Typical float range is +/- 1038. So allowing for 40 or so characters makes sense. An exact print of FLT_TRUE_MIN can take ~150 characters. To distinguish a arbitrarily "float" string from FLT_TRUE_MIN from the next larger one needs about that many digits.
If "float" strings are not arbitrary, but only come from the output of a printed float, then far few digits are needed - about 40.
Of course it is wise to allow for extra leading/trailing spaces and zeros.
You need to take the input as a string and then, make use of strtod() to parse the input.
Regarding the return values, from the man page:
double strtod(const char *nptr, char **endptr);
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.
Getting to the point of detection of errors, couple of points:
Ensure the errno is set to 0 before the call and it still is 0 after the call.
The return value is not HUGE_VAL.
The content pointed to by *endptr is not null and not equal to nptr (i.e., no conversation has been preformed).
The above checks, combined together will ensure a successful conversion.
In your case, the last point is essential, as if there is an invalid character present in the input, the *endptr would not be pointing to a null, instead it would hold the address of that (first) invalid character in the input.
#include<stdio.h>
#include<stdlib.h>
void main(){
char num1[15];
float number1;
int dot_check1=0,check=0,i;
printf("enter the numbers :\n");
gets(num1);
i=0;
while(num1[i]){
if(num1[i]>'/' && num1[i]<':')
;
else { if(dot_check1==0){
if(num1[i]=='.')
dot_check1=1;
else {
check=1;
break;
}
}
else {
check=1;
break;
}
}
i++;
}
if(check){
printf("please check the number you have entered");
}
else{
number1=atof(num1);
printf("you entered number is %f",number1);
}
}
Here is untested code to check whether a string meets the requested specification.
#include <ctype.h>
/* IsFloatNumeral returns true (1) if the string pointed to by p contains a
valid numeral and false (0) otherwise. A valid numeral:
Starts with optional white space.
Has an optional hyphen as a minus sign.
Contains either digits, a period followed by digits, or both.
Ends with optional white space.
Notes:
It is unusual not to accept "3." for a float literal, but this was
specified in a comment, so the code here is written for that.
The question does not state that leading or trailing white space
should be accepted (and ignored), but that is included here. To
exclude such white space, simply delete the relevant lines.
*/
_Bool IsFloatNumeral(const char *p)
{
_Bool ThereAreInitialDigits = 0;
_Bool ThereIsAPeriod = 0;
// Skip initial spaces. (Not specified in question; removed if undesired.)
while (isspace(*p))
++p;
// Allow an initial hyphen as a minus sign.
if (*p == '-')
++p;
// Allow initial digits.
if (isdigit(*p))
{
ThereAreInitialDigits = 1;
do
++p;
while (isdigit(*p));
}
// Allow a period followed by digits. Require at least one digit to follow the period.
if (*p == '.')
{
++p;
if (!isdigit(*p))
return 0;
ThereIsAPeriod = 1;
do
++p;
while (isdigit(*p));
}
/* If we did not see either digits or a period followed by digits,
reject the string (return 0).
*/
if (!ThereAreInitialDigits && !ThereIsAPeriod)
return 0;
// Skip trailing spaces. (Not specified in question; removed if undesired.)
while (isspace(*p))
++p;
/* If we are now at the end of the string (the null terminating
character), accept the string (return 1). Otherwise, reject it (return
0).
*/
return *p == 0;
}

Why can't you just check if errno is equal to ERANGE? [duplicate]

This question already has answers here:
Correct usage of strtol
(5 answers)
Closed 3 years ago.
I've been trying to properly convert a char array to a long with strtol, check if there was an overflow or underflow and then do an int cast on the long. Along the way, I've noticed a lot of code that looks like this
if ((result == LONG_MAX || result == LONG_MIN) && errno == ERANGE)
{
// Handle the error
}
Why can you not just say
if(errno == ERANGE)
{
// Handle the error
}
From my understanding, if an underflow or overflow occur, errno is set to ERANGE in both cases. So is the former really necessary? Could checking ERANGE alone be problematic?
This how my code looks as of now
char *endPtr;
errno = 0;
long result = strtol(str, &endPtr, 10);
if(errno == ERANGE)
{
// Handle Error
}
else if(result > INT_MAX || result < INT_MIN)
{
// Handle Error
}
else if(endPtr == str || *endPtr != '\0')
{
// Handle Error
}
num = (int)result;
return num;
If there is a reason for the former please let me know.
The first code snippet is just plain wrong, and I'll explain why later, but first we need some background.
errno is a thread-local variable. It is set to a non-zero value when a system call or certain library functions fail. It remains unchanged when a system call succeeds. So it always contains the error number from last call that failed.
This means that you have two choices. Either set errno to 0 before each call, or use the standard idiom for errno. Here's the pseudo-code for the standard idiom
if ( foo() == some_value_that_indicates_that_an_error_occurred )
then the value in errno applies to foo
else
foo succeeded and the errno must be ignored because it could be anything
Most programmers will use the standard idiom, because setting errno to 0 before every system call is annoying and repetitive. Not to mention the fact that you might forget to set errno to 0 in the one place it actually matters.
Back to the first code snippet. It is wrong because there is no return value from strtol that unambiguously indicates that strtol failed. If strtol returns LONG_MAX, it could be that an error occurred, or the string actually contained the number LONG_MAX. There's no way to know whether the strtol call succeeded or failed. Which means that the standard idiom (which is what the first code snippet is trying to implement) cannot be used with strtol.
To use strtol correctly, you need to set errno to 0 before the call, like this
errno = 0;
result = strtol( buffer, &endptr, 10 );
if ( errno == ERANGE )
{
// handle the error
// ERANGE is the only error mentioned in the C specification
}
else if ( endptr == buffer )
{
// handle the error
// the conversion failed, i.e. the input string was empty,
// or only contained whitespace, or the first non-whitespace
// character was not valid
}
Note that some implementations define other non-zero values for errno. See the applicable man page for details.
If you call
result = strtol("-2147483648", NULL, 0);
or
result = strtol("2147483647", NULL, 0);
on a 32-bit machine, you're going to get LONG_MIN or LONG_MAX in result, even though there hasn't been an error.
As user3386109 explained, one way to detect errors from strtol is to set errno to 0 first. The other way is to let it give you an end pointer and look at that. There are three or four cases:
char *endptr;
long int result = strtol(str, &endptr, 10);
if(*str == '\0') {
/* str was empty */
} else if(endptr == str) {
/* str was completely invalid */
} else if(*endptr != '\0') {
/* numeric result followed by trailing nonnumeric character(s) */
} else {
/* str was a completely valid number (perhaps with leading whitespace) */
}
Depending on your needs, the first two or three cases may be collapsed together. You may then need to worry (a) whether the "completely valid number" was representable (which you can test using errno), and (b) whether any "trailing nonnumeric character(s)" were innocuous whitespace (which, alas, strtol doesn't check for you, so if you care you'll have to check yourself).

Good C Coding practice/etiquette for integrity checks

Two part question;
I'm Coming from a high level Language, so this is a question about form not function;
I've written an isnumeric() function that takes a char[] and returns 1 if the string is a number taking advantage of the isdigit() function in ctype. Similar functions are builtin to other languages and I have always used something like that to integrity check the data before converting it to a numeric type. Mostly because some languages conversion functions fail badly if you try to convert a non-number string to an integer.
But it seems like a kludge having to do all that looping to compensate for the lack of strings in C, which poses the first part of the question;
Is it acceptable practice in C to trap for a 0 return from atoi() in lieu of doing an integrity check on the data before calling atoi()? The way atoi() (and other ascii to xx functions) works seems to lend itself well to eliminating the integrity check altogether. It would certainly seem more efficient to just skip the check.
The second part of the question is;
Is there a C function or common library function for a numeric integrity check
on a string? (by string, I of course mean char[])
Is it acceptable practice in C to trap for a 0 return from atoi() in lieu of doing an integrity check on the data before calling atoi()?
Never ever trap on error unless the error indicates a programming error that can't happen if there isn't a bug in the code. Always return some sort of error result in case of an error. Look at the OpenBSD strtonum function for how you could design such an interface.
The second part of the question is; Is there a C function or common library function for a numeric integrity check on a string? (by string, I of course mean char[])
Never use atoi unless you are writing a program without error checking as atoi doesn't do any error checking. The strtol family of functions allow you to check for errors. Here is a simply example of how you could use them:
int check_is_number(const char *buf)
{
const char *endptr;
int errsave = errno, errval;
long result;
errno = 0;
result = strtol(buf, &endptr, 0);
errval = errno;
errno = errsave;
if (errval != 0)
return 0; /* an error occured */
if (buf[0] == '\0' || *endptr != '\0')
return 0; /* not a number */
return 1;
}
See the manual page linked before for how the third argument to strtol (base) affects what it does.
errno is set to ERANGE if the value is out of range for the desired type (i.e. long). In this case, the return value is LONG_MAX or LONG_MIN.
If the conversion method returns an error indication (as distinct from going bananas if an error occurs, or not providing a definitive means to check if an error has occurred) then there is actually no need to check if a string is numeric before trying to convert it.
With that in mind, using atoi() is not a particularly good function to use if you need to check for errors on conversion. Zero will be returned for zero input, as well as an error, and there is no way to check on why. A better function to use is (assuming you want to read an integral value) is strtol(). Although strtol() returns zero on integer, it also returns information that can be used to check for failure. For example;
long x;
char *end;
x = strtol(your_string, &end, 10);
if (end == your_string)
{
/* nothing was read due to invalid character or the first
character marked the end of string */
}
else if (*end != '\0`)
{
/* an integral value was read, but there is following non-numeric data */
}
Second, there are alternatives to using strtol(), albeit involving more overhead. The return values from sscanf() (and, in fact, all functions in the scanf() family) can be checked for error conditions.
There is no standard function for checking if a string is numeric, but it can be easily rolled using the above.
int IsNumeric(char *your_string)
{
/* This has undefined behaviour if your_string is not a C-style string
It also deems that a string like "123AB" is non-numeric
*/
long x;
char *end;
x = strtol(your_string, &end, 10);
return !(end == your_string || *end != '\0`);
}
No (explicit) loops in any of the above options.
Is it acceptable practice in C to trap for a 0 return from atoi() in lieu of doing an integrity check on the data before calling atoi()?
No. #FUZxxl well answers that.
Is there a C function or common library function for a numeric integrity check on a string?
In C, the conversion of a string to a number and the check to see if the conversion is valid is usually done together. The function used depends on the type of number sought. "1.23" would make sense for a floating point type, but not an integer.
// No error handle functions
int atoi(const char *nptr);
long atol(const char *nptr);
long long atoll(const char *nptr);
double atof(const char *nptr);
// Some error detection functions
if (sscanf(buffer, "%d", &some_int) == 1) ...
if (sscanf(buffer, "%lf", &some_double) == 1) ...
// Robust methods use
long strtol( const char *nptr, char ** endptr, int base);
long long strtoll( const char *nptr, char ** endptr, int base);
unsigned long strtoul( const char *nptr, char ** endptr, int base);
unsigned long long strtoull( const char *nptr, char ** endptr, int base);
intmax_t strtoimax(const char *nptr, char ** endptr, int base);
uintmax_t strtoumax(const char *nptr, char ** endptr, int base);
float strtof( const char *nptr, char ** endptr);
double strtod( const char *nptr, char ** endptr);
long double strtold( const char *nptr, char ** endptr);
These robust methods use char ** endptr to store the string location where scanning stopped. If no numeric data was found, then *endptr == nptr. So a common test could is
char *endptr;
y = strto...(buffer, ..., &endptr);
if (buffer == endptr) puts("No conversion");
if (*endptr != '\0') puts("Extra text");
If the range was exceed these functions all set the global variable errno = ERANGE; and return a minimum or maximum value for the type.
errno = 0;
double y = strtod("1.23e10000000", &endptr);
if (errno == ERANGE) puts("Range exceeded");
The integer functions allow a radix selection from base 2 to 36. If 0 is used, the leading part of the string "0x", "0X", "0", other --> base 16, 16, 8, 10.
long y = strtol(buffer, &endptr, 10);
Read the specification or help page for more details.
You probably don't need a function to check whether a string is numeric. You will most likely need to convert the string to a number so just do that. Then check if the convertion is successful.
long number;
char *end;
number = strtol(string, &end, 10);
if ((*string == '\0') || (*end != '\0'))
{
// empty string or invalid number
}
the second argument of strtol is used to indicate where the parsing ended (the first non-numeric character). That character will be \0 if we've reached the end of the string. If you want to permit other characters after the number (like ), you can use switch to check for it.
strtol works with long integers. If you need some other type, you should consult the man page: man 3 strtol. For floating-point numbers you can use strtod.
Don't trap if the program logic permits that the string is not numeric (e.g. if it comes from the user or a file).
OP later commneted:
I'm looking for a way to determine if the string contains ONLY base 10 digits or a decimal or a comma. So if the string is 100,000.01 I want a positive return from func. Any other ascii characters anywhere in the string would result in a negative return value.
If is all your interest, use;
if (buffer[strspn(buffer, "0123456789.,")] == '\0') return 0; // Success
else return -1; // Failure

Problem with string conversion to number ( strtod )

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.
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 == ' ')
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
...
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.
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 of strtod to NULL, but use it to check the validity of the converted value, also check for 0.0.
That second argument to strtod, which you've set to NULL, can be a pointer-to-pointer-to-char; the pointer-to-char that it points to will get set to the character after the last thing strtod managed to parse. If that's the end of the string, or at least there's nothing after it but whitespace, then what you had was a number. Otherwise, it was something else.
I don't know much about this language but I do know that strtod() will return 0.0 if the input is wrong. Maybe you could use a regular expression to validate the input string is a number.
OP's code has issues:
getenv() may return NULL
Consider a null pointer test of the result.
Not certainly a string
char strEnv[32];
strncpy(strEnv, getenv("LT_LEAK_START"), 31);
// strEnv is not certainly a string as it may lack a null character.
strEnv[31] = 0; // Add
The end pointer of strtod() is useful, yet deserves more testing
// Conversion problems not detected. See following.
double d = strtod(strEnv, NULL);
char *endptr;
errno = 0;
double d = strtod(strEnv, &endptr);
if (d == endptr) {
return Error_No_conversion; // Like "", "+", "-.", "abc"
}
// Tolerate trailing white-space as leading space is OK
while (isspace(((unsigned char *)endptr)[0])) {
endptr++;
}
if (*endptr) {
return Error_Junk_after_number; // Like "876 - 5309"
}
// Optional pedantic testing.
if (errno == ERANGE) {
if (fabs(d) > 1.0) {
// Usually this is OK to just continue;
// `d` will have the signed value of HUGE_VAL (DBL_MAX or infinity)
; // return Error_Number_too_large;
} else {
// Usually this is OK to just continue;
// `d` will have the signed value of DBL_MIN or 0.0 or some small value
; // return Error_Number_too_small;
}
} else if (errno) {
// Usually this is OK to just continue;
; return Error_Implementation_specific_error;
}
// Success, now use `d`.
So far, this answer does not fail "" nor "123 456".

What is the difference between sscanf or atoi to convert a string to an integer?

gcc 4.4.4 c89
What is better to convert a string to an integer value.
I have tried 2 different methods atoi and sscanf. Both work as expected.
char digits[3] = "34";
int device_num = 0;
if(sscanf(digits, "%d", &device_num) == EOF) {
fprintf(stderr, "WARNING: Incorrect value for device\n");
return FALSE;
}
or using atoi
device_num = atoi(digits);
I was thinking that the sscanf would be better as you can check for errors. However, atoi doesn't doing any checking.
You have 3 choices:
atoi
This is probably the fastest if you're using it in performance-critical code, but it does no error reporting. If the string does not begin with an integer, it will return 0. If the string contains junk after the integer, it will convert the initial part and ignore the rest. If the number is too big to fit in int, the behaviour is unspecified.
sscanf
Some error reporting, and you have a lot of flexibility for what type to store (signed/unsigned versions of char/short/int/long/long long/size_t/ptrdiff_t/intmax_t).
The return value is the number of conversions that succeed, so scanning for "%d" will return 0 if the string does not begin with an integer. You can use "%d%n" to store the index of the first character after the integer that's read in another variable, and thereby check to see if the entire string was converted or if there's junk afterwards. However, like atoi, behaviour on integer overflow is unspecified.
strtol and family
Robust error reporting, provided you set errno to 0 before making the call. Return values are specified on overflow and errno will be set. You can choose any number base from 2 to 36, or specify 0 as the base to auto-interpret leading 0x and 0 as hex and octal, respectively. Choices of type to convert to are signed/unsigned versions of long/long long/intmax_t.
If you need a smaller type you can always store the result in a temporary long or unsigned long variable and check for overflow yourself.
Since these functions take a pointer to pointer argument, you also get a pointer to the first character following the converted integer, for free, so you can tell if the entire string was an integer or parse subsequent data in the string if needed.
Personally, I would recommend the strtol family for most purposes. If you're doing something quick-and-dirty, atoi might meet your needs.
As an aside, sometimes I find I need to parse numbers where leading whitespace, sign, etc. are not supposed to be accepted. In this case it's pretty damn easy to roll your own for loop, eg.,
for (x=0; (unsigned)*s-'0'<10; s++)
x=10*x+(*s-'0');
Or you can use (for robustness):
if (isdigit(*s))
x=strtol(s, &s, 10);
else /* error */
*scanf() family of functions return the number of values converted. So you should check to make sure sscanf() returns 1 in your case. EOF is returned for "input failure", which means that ssacnf() will never return EOF.
For sscanf(), the function has to parse the format string, and then decode an integer. atoi() doesn't have that overhead. Both suffer from the problem that out-of-range values result in undefined behavior.
You should use strtol() or strtoul() functions, which provide much better error-detection and checking. They also let you know if the whole string was consumed.
If you want an int, you can always use strtol(), and then check the returned value to see if it lies between INT_MIN and INT_MAX.
To #R.. I think it's not enough to check errno for error detection in strtol call.
long strtol (const char *String, char **EndPointer, int Base)
You'll also need to check EndPointer for errors.
Combining R.. and PickBoy answers for brevity
long strtol (const char *String, char **EndPointer, int Base)
// examples
strtol(s, NULL, 10);
strtol(s, &s, 10);
When there is no concern about invalid string input or range issues, use the simplest: atoi()
Otherwise, the method with best error/range detection is neither atoi(), nor sscanf().
This good answer all ready details the lack of error checking with atoi() and some error checking with sscanf().
strtol() is the most stringent function in converting a string to int. Yet it is only a start. Below are detailed examples to show proper usage and so the reason for this answer after the accepted one.
// Over-simplified use
int strtoi(const char *nptr) {
int i = (int) strtol(nptr, (char **)NULL, 10);
return i;
}
This is the like atoi() and neglects to use the error detection features of strtol().
To fully use strtol(), there are various features to consider:
Detection of no conversion: Examples: "xyz", or "" or "--0"? In these cases, endptr will match nptr.
char *endptr;
int i = (int)strtol(nptr, &endptr, 10);
if (nptr == endptr) return FAIL_NO_CONVERT;
Should the whole string convert or just the leading portion: Is "123xyz" OK?
char *endptr;
int i = (int)strtol(nptr, &endptr, 10);
if (*endptr != '\0') return FAIL_EXTRA_JUNK;
Detect if value was so big, the the result is not representable as a long like "999999999999999999999999999999".
errno = 0;
long L = strtol(nptr, &endptr, 10);
if (errno == ERANGE) return FAIL_OVERFLOW;
Detect if the value was outside the range of than int, but not long. If int and long have the same range, this test is not needed.
long L = strtol(nptr, &endptr, 10);
if (L < INT_MIN || L > INT_MAX) return FAIL_INT_OVERFLOW;
Some implementations go beyond the C standard and set errno for additional reasons such as errno to EINVAL in case no conversion was performed or EINVAL The value of the Base parameter is not valid.. The best time to test for these errno values is implementation dependent.
Putting this all together: (Adjust to your needs)
#include <errno.h>
#include <stdlib.h>
int strtoi(const char *nptr, int *error_code) {
char *endptr;
errno = 0;
long i = strtol(nptr, &endptr, 10);
#if LONG_MIN < INT_MIN || LONG_MAX > INT_MAX
if (errno == ERANGE || i > INT_MAX || i < INT_MIN) {
errno = ERANGE;
i = i > 0 : INT_MAX : INT_MIN;
*error_code = FAIL_INT_OVERFLOW;
}
#else
if (errno == ERANGE) {
*error_code = FAIL_OVERFLOW;
}
#endif
else if (endptr == nptr) {
*error_code = FAIL_NO_CONVERT;
} else if (*endptr != '\0') {
*error_code = FAIL_EXTRA_JUNK;
} else if (errno) {
*error_code = FAIL_IMPLEMENTATION_REASON;
}
return (int) i;
}
Note: All functions mentioned allow leading spaces, an optional leading sign character and are affected by locale change. Additional code is required for a more restrictive conversion.
Note: Non-OP title change skewed emphasis. This answer applies better to original title "convert string to integer sscanf or atoi"
If user enters 34abc and you pass them to atoi it will return 34.
If you want to validate the value entered then you have to use isdigit on the entered string iteratively

Resources