需要解释C程序输出

我运行以下程序,我在输出中得到一个意外的数字。

输入要检查的号码

9999999999

141006540​​7是素数

我在输出中得到一个不同的数字。 我输入了9999999999,输出中看到了141006540​​7。 有人可以解释这是怎么回事吗? 看起来我超出了整数域的范围。

#include #include void main() { int n,i; printf("Enter the number to be checked\n"); scanf("%d",&n); i=2; while(i<n) { if(n%i==0) { printf("%d is not a prime number\n", n); exit(0); } i++; } printf("%d is a prime number\n", n); } 

9,999,999,999 (十九秒)是适合您的int数据类型。 如果你计算出它与1,410,065,407之间的差异,你会发现它的精确度为2(确切地说是2 33 ),这意味着它在你扫描时会缠绕。

通过“缠绕”,我指的是整数的属性,只需将它们的最大值环绕以成为意外的东西。

例如,一个8位无符号整数可以保存值0..255 ,当你将一个加到一个保持255的变量时,它将变为零(有符号值往往会从最大正值换算到最小负值,最小值在这种情况下,最远离零的意思)。

因此,假设您正在读取十进制数字,其中类型的范围为0..255并且数字的字符串表示forms为456 。 以下“代码”大概是如何工作的:

 def scanNum(s): result = 0 for each character c in s: result = result * 10 + value(c) return result 
  • 处理4字符时, result乘以10,0 0 * 10 = 0 ,然后再加4,得4
  • 处理5字符时, result乘以10,4 4 * 10 = 40 ,然后再加5,得45
  • 当处理6字符时, result乘以45 * 10 = 450 但是,因为你只能代表0..255 ,它会回绕,给你450 - 256 = 194 。 然后你加6,给200

你可以看到你想要的和你得到的之间的差异也与范围非常相关: 456 - 200 = 256

如果你用九个 9秒(或999,999,999 ,考虑到32位二进制补码代表的最大数字是2,147,483,647 ),或者使用能够容纳更大数字的数据类型,你可能会发现它没关系:

 #include  #include  int main (void) { long long n; printf("Enter the number to be checked\n"); scanf("%lld",&n); printf("%lld\n", n); return 0; } 

我原本认为根据标准这是错误的,因为根据C11 7.21.6.2 The fscanf function /12 ,它C11 7.21.6.2 The fscanf function /12 strtol函数:

d匹配可选带符号的十进制整数,其格式与strtol函数的主题序列的预期格式相同,基本参数的值为10。 相应的参数应该是指向有符号整数的指针。

strtol函数, C11 7.22.1.4 The strtol, strtoll, strtoul, and strtoull functions /8个状态:

如果正确的值超出可表示值的范围,则返回LONG_MIN,LONG_MAX,LLONG_MIN,LLONG_MAX,ULONG_MAX或ULLONG_MAX(根据值的返回类型和符号,如果有)。

但是,实际上,只有格式遵循该function。 fscanf及其兄弟的结果C11 7.21.6.2 The fscanf function /10控制C11 7.21.6.2 The fscanf function /10

如果此对象没有适当的类型,或者无法在对象中表示转换结果,则行为未定义。

所以,如果它超出范围你得到的数字可以是任何东西,事实上,鉴于对未定义行为的结果缺乏限制,它可以做任何事情,而不仅仅是返回一个狡猾的结果,包括格式化你的磁盘和崩溃当地时空陷入赤裸裸的奇点:-)

在这种情况下,它似乎只是将值包装为扫描过程的一部分,这是代码最简单的事情。