9,999,999,999
(ten 9
s) is to big to fit into your int
data type. If you work out the difference between that and 1,410,065,407
, you'll see it's an exact power of two (233 to be exact), meaning that it wrapped around while you were scanning it in.
By "wrapped around", I refer to the property of integers to simply wrap around at their maximum value to become something unexpected.
For example, an eight-bit unsigned integer which can hold the values 0..255
will, when you add one to a variable holding 255
, become zero (signed values tend to wrap from the largest positive value to the smallest negative value, smallest meaning furthest from zero in this case).
So let's say you're reading in a decimal number where the type has a range of 0..255
and the string representation of the number is 456
. The following "code" would be roughly how it works:
def scanNum(s):
result = 0
for each character c in s:
result = result * 10 + value(c)
return result
- When processing the
4
character, result
is multiplied by ten, 0 * 10 = 0
, and you then add four, giving 4
.
- When processing the
5
character, result
is multiplied by ten, 4 * 10 = 40
, and you then add five, giving 45
.
- When processing the
6
character, result
is multiplied by ten, 45 * 10 = 450
but, because you can only represent 0..255
, it wraps around, giving you 450 - 256 = 194
. And you then add six, giving 200
.
You can see there that the difference between what you want and what you get is very much related to the range as well: 456 - 200 = 256
.
If you try it with nine 9
s (or 999,999,999
, keeping in mind the largest number representable with 32-bit two's complement is larger at 2,147,483,647
), or use a data type able to hold larger numbers, you'll probably find it's okay:
#include <stdio.h>
#include <stdlib.h>
int main (void) {
long long n;
printf("Enter the number to be checked\n");
scanf("%lld",&n);
printf("%lld\n", n);
return 0;
}
I originally thought this was wrong according to the standard since, as per C11 7.21.6.2 The fscanf function /12
, it defers to the strtol
function:
d Matches an optionally signed decimal integer, whose format is the same as expected for the subject sequence of the strtol function with the value 10 for the base argument. The corresponding argument shall be a pointer to signed integer.
and the strtol
function, C11 7.22.1.4 The strtol, strtoll, strtoul, and strtoull functions /8
states:
If the correct value is outside the range of representable values, LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX, ULONG_MAX, or ULLONG_MAX is returned (according to the return type and sign of the value, if any).
But, in actuality, only the format defers to that function. The result for fscanf
and its brethren is controlled by C11 7.21.6.2 The fscanf function /10
:
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.
So, the number you get back if it's out of range can be anything and, in fact, given the lack of limitations on the results of undefined behaviour, it could do anything rather than just returning a dodgy result, including formatting your disks and collapsing local space-time into a naked singularity :-)
In this case, it appears to simply wrap the value around as part of the scanning process, the simplest thing for the code to do.