What is the difference between sscanf or atoi to convert a string to an integer?
CScanfAtoiC Problem Overview
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.
C Solutions
Solution 1 - C
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 */
Solution 2 - C
*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
.
Solution 3 - C
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.
Solution 4 - C
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);
Solution 5 - C
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 matchnptr
.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 notlong
. Ifint
andlong
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 orEINVAL
The value of the Base parameter is not valid.. The best time to test for theseerrno
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"
Solution 6 - C
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