1

我正在学习Robert Sedgewick在C++算法中的C++。现在我正在使用Eratosthenes的Sieve,并且在用户指定的最大素数上限上工作。当我使用max 46349运行代码时,它运行并打印出所有素数达46349,但是当我使用max 46350运行代码时,会发生分段错误。有人可以帮助解释为什么吗?C++数组分配分割错误11新手

./sieve.exe 46349 
2 3 5 7 11 13 17 19 23 29 31 ... 

./sieve.exe 46350 
Segmentation fault: 11 

代码:

#include<iostream> 

using namespace std; 

static const int N = 1000; 

int main(int argc, char *argv[]) { 
    int i, M; 

    //parse argument as integer 
    if(argv[1]) { 
     M = atoi(argv[1]); 
    } 

    if(not M) { 
     M = N; 
    } 

    //allocate memory to the array 
    int *a = new int[M]; 

    //are we out of memory? 
    if(a == 0) { 
     cout << "Out of memory" << endl; 
     return 0; 
    } 

    // set every number to be prime 
    for(i = 2; i < M; i++) { 
     a[i] = 1; 
    } 

    for(i = 2; i < M; i++) { 
     //if i is prime 
     if(a[i]) { 
      //mark its multiples as non-prime 
      for(int j = i; j * i < M; j++) { 
       a[i * j] = 0; 
      } 
     } 
    } 

    for(i = 2; i < M; i++) { 
     if(a[i]) { 
      cout << " " << i; 
     }  
    } 
    cout << endl; 

    return 0; 
} 
+0

分段错误通常是由超出分配内存边界的写入引起的。您应该使用调试器(或添加打印语句)来跟踪程序的进度,以便找出发生这种情况的时间点。 – 2013-03-02 17:00:04

+4

请注意,如果分配失败,'new'不会返回'NULL'(除非指定'nothrow',否则它不在此处)。它会抛出一个'std :: bad_alloc'异常。 – Cornstalks 2013-03-02 17:00:41

回答

1

我看,问题声明中号为int。当我宣布我,M和J只要,这似乎工作正常。

+1

我不会指望'长'这样做。 'long'至少为32位,任何32位的实现都会导致溢出。不过,long long至少是64,而且它正式成为C++ 11的一部分。如果处理器是32位处理器并且处理64位数字的话,那么速度可能会有问题,但我甚至不知道,直到我有多少时间才会有多少差异。 – chris 2013-03-02 17:03:15

+0

正如'NPE'所示,如果'int'是32位,那么'i * j'将溢出并且可能发生不好的事情(如崩溃)。如果'long'有更多的位,那么使它成为'long'将会工作,对于你和你的编译器来说,'long'可能是64位,所以'i * j'不再溢出。 – Cornstalks 2013-03-02 17:05:03

1

在任何合理的现代C++中,如果分配失败,您将不会从new返回空指针,除非您使用非抛出new。您的代码部分无法按预期工作 - 您必须将std::bad_alloc可能从呼叫中发出,而不是new

你也想声明你的数组索引类型为size_t

+0

你会推荐任何关于这方面的学习资料吗?我对这种语言完全陌生,而且还没有接触到内存管理。 – 2013-03-02 17:07:43

+2

@DavidWilliams,[好书](http://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list)总是一个好的开始。请记住,现代C++不像内存管理那么重要,就像RAII一样,你不需要管理它。 – chris 2013-03-02 17:10:46

5

你有整数溢出这里:

 for(int j = i; j * i < M; j++) { 
      a[i * j] = 0; 
     } 

46349 * 46349不适合在int

在我的机器,改变jlong类型能够运行程序较大输入:

for(long j = i; j * i < M; j++) { 

取决于你的编译器与架构,你可能需要使用long long得到同样的影响。

3

当您使用调试器运行您的程序,你会看到它失败在

a[i * j] = 0; 

i * j溢出并产生负。这个负数小于M,这就是为什么它再次进入循环,然后失败访问a[-2146737495]

+0

迂腐,我相信你*知道这一点,但它技术上不一定是-2146737495。 – chris 2013-03-02 17:09:41

+0

@chris这只是从gdb剪切和粘贴。 – 2013-03-02 17:16:13