Segfault同时循环

时间:2014-05-01 00:35:33

标签: c++

解决一个简单的问题,但由于程序正在写入数组的末尾而导致分段错误。

#include <iostream>
#include <stdio.h>

static const int N = 46350;

int main()
{
    int* intarray = new int[N];

    for (int i = 2; i < N; ++i)
    {
        intarray[i] = 1;
    }

    for (int i = 2; i < N; ++i)
    {
        if (intarray[i])
        {
            for (int j = i; j*i < N; ++j)
            {
                printf("before i: %i j: %i ", i, j);
                std::cout << "a: " << intarray + i*j << std::endl;
                intarray[i*j] = 0;
                printf("after  i: %i j: %i ", i, j);
                std::cout << "a: " << intarray + i*j << std::endl;
            }
        }
    }

    delete [] intarray;
    return 0;
}

控制台输出:

before i: 211 j: 219 array: 0x21dd24c
after  i: 211 j: 219 array: 0x21dd24c
before i: 46349 j: 46349 array: 0x2488aec

对于N = 46349,这不会发生。不确定发生了什么。

2 个答案:

答案 0 :(得分:3)

整数溢出导致了这种情况。 ij的乘积溢出了int类型的范围并产生负值,显然比较为“小于N”。稍后您尝试修改该负索引i * j的内存,这会导致不可预测的结果。实际上,溢出本身已经产生了未定义的行为。

对于N的此值,您可以使用unsigned int类型而不是int类型来逃避。前者的正范围大两倍。但在一般情况下,您必须记住,两个int值的乘积不一定符合int类型的范围。

在您的情况下i可以变得与46349和46349 * 46349 = 2148322500一样大,这大于有符号2的补码32位整数2147483647的典型上限。

N = 463549的版本正式也以同样的方式被打破,除了你幸运的是那个版本。 if (intarray[i])检查可防止内循环在导致溢出的情况下运行。

答案 1 :(得分:0)

您的案例中的最大整数(int)为2^31-1,即2147483647。该数字的平方根为46340.95...因此,当您乘以i * j时,您会得到一个整数溢出,结果看起来是负数,它看起来是< N并且在循环中被允许通过。所以你得到了一个错误。实际上,任何高于46340的东西都会出现问题。