int i, f;
f = scanf("%d", &i);
When I enter input as 3333333333333333333333 (greater than the capacity of int). Shouldn't the value of f be 0?
Shouldnt the value of f be 0?
With standard C, no. With scanf("%d",&i), on int overflow, the result is undefined.
With scanf() in Unix (of which there are variations), I find no prevention of undefined behavior with overflow.
Best to ditch (not use) scanf() and use fgets() for all user input.
Code could try a textual width limit and a wider type:
intmax_t bigd;
// vv --- width limit
if (scanf("%18jd",&bigd) == 1 && bigd >= INT_MIN && bigd <= INT_MAX) {
d = (int) bigd;
} else {
puts("Oops");
}
Yet that has trouble on novel implementations where int is as wide as intmax_t.
scanf() returns 0 when no int textual input found.
A key design element missing from OP's questions is what should happen to user input that exceeds the int range? Stop reading after the first `"333333333"?
What is best, depends on how OP wants to handle, in detail, error conditions - something not yet stated.
No, it can't be detected that way.
The below is not a portable solution, but it works in gcc12.1, clang14.0 and msvc19.32. It may stop working in later releases.
You need to set errno = 0; first and then check it for range errors:
#include <errno.h>
// ...
errno = 0;
f = scanf("%d",&i);
if(f == 1 && errno != ERANGE) {
// success
}
For portability, read this from an early draft of the C2x standard:
Unless assignment suppression was indicated by a
*, the result of the conversion is placed in the object pointed to by the first argument following the format argument that has not already received a conversion result. If this object does not have an appropriate type, or if the result of the conversion cannot be represented in the object, the behavior is undefined.
A better (as in portable) option to detect this would be to read into a char[] buffer first and then use strtol() to convert it to a number. From the same standard draft:
The
strtol,strtoll,strtoul, andstrtoullfunctions return the converted value, if any. If no conversion could be performed, zero is returned. If the correct value is outside the range of representable values,LONG_MIN,LONG_MAX,LLONG_MIN,LLONG_MAX,ULONG_MAX, orULLONG_MAXis returned (according to the return type and sign of the value, if any), and the value of the macroERANGEis stored inerrno.
Here's a demonstrative program using strtol() (which converts to long):
#include <ctype.h>
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
// A wrapper around `strtol` to convert to `int`
int strtoi(const char *str, char **str_end, int base) {
int errno_save = errno;
errno = 0; // clear it from any previous error (must be done)
long result = strtol(str, str_end, base);
if(errno == ERANGE) return result == LONG_MAX ? INT_MAX : INT_MIN;
if(result > INT_MAX || result < INT_MIN) {
errno = ERANGE;
return result > INT_MAX ? INT_MAX : INT_MIN;
}
// success or no conversion could be performed
errno = errno_save; // restore errno
return (int)result;
}
#define Size(x) (sizeof (x) / sizeof *(x))
int main(void) {
const char* strings[] = {
"3333333333333333333333 foo",
"2147483647 will probably succeed",
"2147483648 will probably fail",
"32767 guaranteed success",
"32767xyz",
"xyz",
"123",
""
};
char *end; // this will point at where the conversion ended in the string
for(unsigned si = 0; si < Size(strings); ++si) {
printf("testing \"%s\"\n", strings[si]);
errno = 0; // clear it from any previous error (must be done)
int result = strtoi(strings[si], &end, 10);
if(errno == ERANGE) {
perror(" to big for an int");
} else if(strings[si] == end) {
fprintf(stderr, " no conversion could be done\n");
} else if(*end != '\0' && !isspace((unsigned char)*end)) {
fprintf(stderr, " conversion ok,"
" but followed by a rouge character\n");
} else {
printf(" success: %d rest=[%s]\n", result, end);
}
}
}
Possible output:
testing "3333333333333333333333 foo"
to big for an int: Numerical result out of range
testing "2147483647 will probably succeed"
success: 2147483647 rest=[ will probably succeed]
testing "2147483648 will probably fail"
to big for an int: Numerical result out of range
testing "32767 guaranteed success"
success: 32767 rest=[ guaranteed success]
testing "32767xyz"
conversion ok, but followed by a rouge character
testing "xyz"
no conversion could be done
testing "123"
success: 123 rest=[]
testing ""
no conversion could be done
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With