为何在线判断运行时错误?

时间:2013-08-14 07:38:37

标签: c runtime-error

我无法理解为什么我在使用此代码时出现运行时错误。问题是每个数字> = 6可以表示为两个素数的总和。 我的代码是......提前感谢问题链接是http://poj.org/problem?id=2262

#include "stdio.h"
#include "stdlib.h"
#define N 1000000

int main()
{

    long int i,j,k;
    long int *cp = malloc(1000000*sizeof(long int));
    long int *isprime = malloc(1000000*sizeof(long int));
    //long int *isprime;
    long int num,flag;
    //isprime = malloc(2*sizeof(long int));
    for(i=0;i<N;i++)
    {
        isprime[i]=1;
    }
    j=0;
    for(i=2;i<N;i++)
    {
        if(isprime[i])
        {
            cp[j] = i;
            j++;
            for(k=i*i;k<N;k+=i)
            {
                isprime[k] = 0;
            }
        }
    }
    //for(i=0;i<j;i++)
    //{
    //    printf("%d ",cp[i]);
    //}
    //printf("\n");
    while(1)
    {
        scanf("%ld",&num);
        if(num==0) break;
        flag = 0;
        for(i=0;i<j&&num>cp[i];i++)
        {
            //printf("%d ",cp[i]);
            if(isprime[num-cp[i]])
            {
                printf("%ld = %ld + %ld\n",num,cp[i],num-cp[i]);
                flag = 1;
                break;
            }
        }
        if(flag==0)
        {
            printf("Goldbach's conjecture is wrong.\n");
        }
    }
    free(cp);
    free(isprime);
    return 0;
}

3 个答案:

答案 0 :(得分:1)

立刻浮现出两个可能性。第一个是如果正在使用的测试工具没有提供任何输入,则用户输入可能会失败。在不了解线束的更多细节的情况下,这是最好的猜测。

您可以通过硬编码值来检查,而不是接受标准输入中的值。

另一种可能性是进行了相当大的内存分配。可能是你处于一个不允许的环境中。

一个简单的测试就是删除N的值(顺便说一下,使用它而不是1000000次调用中的多个硬编码malloc数字。更好的方法是检查malloc的返回值,以确保它不是NULL。无论如何应该这样做。

除此之外,您可能需要查看您的Eratosthenes Sieve代码。应该为素数i标记为非素数的第一个项目是i + i,而不是i * i。我认为应该是:

for (k = i + i; k < N; k += i)

数学算法实际上是可以的,因为N小于N * N的任何倍数都已经被标记为非素数,因为它是一个倍数之前检查的素数。

你的问题在于整数溢出。在N变为46_349时,N * N2_148_229_801,如果您有32位二进制补码整数(最大值2_147_483_647),将环绕到-2_146_737_495

当发生这种情况时,循环继续进行,因为负数仍然小于你的限制,但是,我们说,使用它作为数组索引是不可取的: - )

它与i + i一起使用的原因是因为您的限制远远超过INT_MAX / 2,因此不会发生溢出。

如果您想确定,如果您在INT_MAX / 2附近起床,这不会有问题,您可以使用以下内容:

for (k = i + i; (k < N) && (k > i); k += i)

k的额外检查应该捕获环绕事件,只要你的包装遵循“正常”行为 - 技术上,我认为它是未定义的行为来包装但是大多数实现只是包装两个由于两者的补充性质,积极回到负面。请注意,这实际上是不可移植的,但这在实践中意味着它只适用于99.999%的机器: - )

但是,如果你是一个可移植的坚持者,那么首先有更好的方法可以防止溢出。我不会在这里讨论它们,而是说它们涉及减去MAX_INT中总和的一个术语,并将其与另一个求和项进行比较。

答案 1 :(得分:0)

如果我向scanf()输入一个大于1000000或小于1的值,我唯一可以得到错误的方法就是。

像这样:

ubuntu@amrith:/tmp$ ./x
183475666
Segmentation fault (core dumped)
ubuntu@amrith:/tmp$

但其原因应该是显而易见的。除此之外,这段代码看起来不错。

答案 2 :(得分:0)

试图找出问题所在!

如果您使用的操作系统sizeof(long int)4 bytes,则会出现此问题。 在代码中:

for(k=i*i;k<N;k+=i)
{
    isprime[k] = 0;
}

此处,当您执行k = i*i时,对于i的较大值,k的值超出4 bytes并被截断,这可能会导致负数,因此,满足条件k<N,但负数为:)。所以你在那里遇到了分段错误。

您只需要i+i,这很好,但如果您需要增加限制,请注意这个问题。