内存管理-C++数组分配分段故障11新手

memory management - C++ Array Allocation Segmentation Fault 11 Newbie

本文关键字:故障 新手 分段 分配 管理 -C++ 数组 内存      更新时间:2023-10-16

我正在从Robert Sedgewick的《C++中的算法》学习C++。现在我正在研究Eratosthenes筛,它有一个用户指定的最大素数的上界。当我运行最大值为46349的代码时,它会运行并打印出46349之前的所有素数,但当我运行最小值为46350的代码时会出现Segmentation错误。有人能帮忙解释一下原因吗?

./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;
}

此处存在整数溢出:

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

CCD_ 1不适合CCD_。

在我的机器上,将j的类型更改为long可以为更大的输入运行程序:

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

根据编译器和体系结构的不同,您可能必须使用long long才能获得相同的效果。

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

a[i * j] = 0;

CCD_ 6溢出并变为负。这个负数小于M,这就是为什么它再次进入循环,然后在访问a[-2146737495]时失败。

我明白了,问题是将M声明为int。当我将I、M和j声明为长时,这似乎很好。

在任何合理现代的C++中,如果分配失败,除非使用非抛出的new,否则不会从new返回null指针。代码的这一部分不会像您期望的那样工作——您必须捕获可能从对46349 * 463490的调用中发出的std::bad_alloc

您还需要将数组索引声明为类型size_t