2014-05-01 188 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的任何東西都可能會出現問題。