需要解释C程序输出

时间:2015-01-18 05:03:12

标签: c

我运行以下程序,输出中出现意外数字。

输入要检查的号码

9999999999

141006540​​7是素数

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

#include<stdio.h>
#include<stdlib.h>
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);

}

1 个答案:

答案 0 :(得分:3)

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

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

例如,一个8位无符号整数可以保存值0..255,当你向保持255的变量添加一个时,它将变为零(有符号值倾向于从最大的正值中包裹)值为最小的负值,在这种情况下最小的含义为零。)

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

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

您可以看到,您想要的内容与获得的内容之间的差异与范围非常相关:456 - 200 = 256

如果您使用 9 9 s(或999,999,999进行尝试,请记住,在{{1}处,32位二进制补码可表示的最大数字更大}),或使用能够容纳更大数字的数据类型,您可能会发现它没关系:

2,147,483,647

我原本认为根据标准这是错误的,因为根据#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; } ,它遵循C11 7.21.6.2 The fscanf function /12函数:

  

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

strtol函数,strtol表示:

  

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

但实际上,只有格式遵循该功能。 C11 7.22.1.4 The strtol, strtoll, strtoul, and strtoull functions /8及其兄弟的结果fscanf控制:

  

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

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

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