2014-05-01 105 views
0

通过一个简单的问题工作,但由于程序正在写入数组末尾而出现段错误。段循环时段故障

#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.不知道发生了什么事情。

回答

3

整数溢出正在造成这种情况。 ij的乘积溢出int类型的范围,并产生负值,显然将其比作“小于N”。稍后,您尝试修改负指数i * j的记忆,这会导致不可预知的结果。事实上,溢出本身已经产生了未定义的行为。

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

在你的情况i可以变得大到46349和46349 * 46349 = 2148322500,这比签署的典型上限二进制补码的32位整数2147483647

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

0

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