我正在从Robert Sedgewick的C ++中的Algorithms学习C ++。现在我正在研究Eratosthenes的Sieve,用户指定最大素数的上限。当我使用max 46349运行代码时,它运行并打印出所有质数,最高可达46349,但是当我运行max 46350的代码时,会发生分段错误。有人可以帮忙解释原因吗?
./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 :(得分:5)
这里有整数溢出:
for( int j = i; j * i < M; j++ ) {
a[i * j] = 0;
}
46349 * 46349
不适合int
。
在我的计算机上,将j
的类型更改为long
可以为更大的输入运行程序:
for( long j = i; j * i < M; j++ ) {
根据您的编译器和体系结构,您可能必须使用long long
才能获得相同的效果。
答案 1 :(得分:3)
使用调试器运行程序时,您会看到它在
处失败a[i * j] = 0;
i * j
溢出并变为负面。此负数小于M
,这就是为什么它再次进入循环然后无法访问a[-2146737495]
。
答案 2 :(得分:1)
我知道,问题是将M声明为int。当我宣布i,M和j为止时,这似乎工作正常。
答案 3 :(得分:1)
在任何相当现代的C ++中,如果分配失败,除非使用非抛出的新函数,否则不会从new返回空指针。您的代码中的那部分内容无法正常运行 - 您必须抓住可能会从std::bad_alloc
调用中发出的new
。
您还希望将数组索引声明为size_t
类型。