繁体   English   中英

当我的数组太大时出现分段错误

[英]Segmentation fault when my array is too big

编辑:似乎错误只是 9,999,999,999,999 对于数组来说太大了。

我在我的代码中收到此错误“程序接收到信号 sigsegv 分段错误”。

基本上我的代码是做一个 integer 分解,这个练习可以在 codeabbey 上看到 基本上我会收到像 1000 和 output 这样的输入,作为它们的因子的乘积,在这种情况下是 2*2*2*5*5*5。

我通过使用埃拉托色尼筛法生成的质数向量来执行上述操作。

根据网站,输入的位数不会超过 13,因此我的最高数字是 9,999,999,999,999。 下面是我的代码。

#include <iostream>
#include <vector>
#include <cstring>

unsigned long long int MAX_LIMIT = 9999999999999;


std::vector<unsigned long long int> intFactorisation (unsigned long long int num) {
    std::vector<unsigned long long int> answers;
    static std::vector<unsigned long long int> primes;
    if (primes.empty()) {               // generate prime numbers using sieve method
        bool *arr = new bool[MAX_LIMIT];
        memset (arr, true, MAX_LIMIT);
        for (unsigned long long int x = 2; x*x < MAX_LIMIT; x++) {
            if (arr[x] == true) {
                for (unsigned long long int y = x*x; y < MAX_LIMIT; y += x) {

                    arr[y] = false;  // THIS LINE ALWAYS HAS AN ERROR!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

                }
            }
        }
        for (unsigned long long int x = 2; x <= MAX_LIMIT; x++) {
            if (arr[x]) {
                primes.push_back(x);
            }
        }
    }
    std::vector<unsigned long long int>::iterator it = primes.begin();  // start the factorisation
    while(it != primes.end()) {
        if (num % *it == 0) {
            answers.push_back(*it);
            num/=*it;
        }
        else {
            it++;
        }
        if (num == 1) {
            break;
        }
    }

    return answers;
}


int main() {


    int maxi;
    std::cin >> maxi;
    int out[maxi];
    for (int x = 0; x < maxi; x++) {
        std::cin >> out[x];
    }

    for (auto it : out) {
        std::vector<unsigned long long int> temp = intFactorisation(it);
        for (std::vector<unsigned long long int>::iterator it = temp.begin();
            it != temp.end(); it++) {
            if (it == temp.end() - 1) {
                std::cout << *it << " ";
            }
            else {
                std::cout << *it << "*";
            }
        }
    }

}

但是,出于某种原因,程序将始终在 function intFactorisation 中的 arr[y] = false 处终止。 使用 CodeBlocks 时,我会在屏幕左下角看到一条给出分段错误消息的通知。

我已经在我的大得离谱的阵列上使用了“新”,所以 memory 应该在堆上。 我试过使用较小的 MAX_LIMIT,例如 100,000,我的 function 有效。 任何人都知道为什么?

另外,我想知道为什么我不需要取消引用我的指针 arr。 例如,arr[y] = false 有效,但 *arr[y] 或 (*arr)[y] 无效。 希望这也能得到澄清。

感谢您阅读本文,感谢您的帮助。

发布的代码中有两种类型的问题,即 memory 管理和算法。

资源获取

该方案展示了三种memory分配:

  • 变长数组 main中, out被声明为int out[maxi]maxi是一个变量,而不是编译时常量。 这是一个 C99 特性,它从来没有成为任何 C++ 标准的一部分,即使它被某些编译器作为一个特性提供。

  • bool *arr = new bool[MAX_LIMIT]; . 现代指南建议避免使用 bare new来分配 memory 并更喜欢智能指针、标准容器并且通常遵循RAII习惯用法,但这甚至不是这里的主要问题。 MAX_LIMIT太大,不会导致std::bad_alloc异常,并且永远不会调用delete

    在同一个 function 中还有一个循环,它最终会越界访问(不太可能)分配的 memory: for (unsigned long long int x = 2; x <= MAX_LIMIT; x++) { if (arr[x]) { , x 最终会变成 MAX_LIMIT,但你会在 memory 之前用完。

  • std::vector 就是这样,如果程序不会尝试用所有素数填充矢量primes数直到MAX_LIMIT ,即 10 13 -1 或假设 64 位类型将近 80TB。

算法

这个想法是首先计算所有可能的素数,然后对于每个输入的数字,检查它们中的任何一个是否是一个因子。 问题在于最大可能数是一个非常大的数,但好消息是您不需要计算和存储不超过该数的所有素数,而只需计算其平方根即可。

想象一下,已经尝试了直到那个平方根(我们称之为 S)的所有素数,然后将原始数除以找到的任何因子。 如果仍有余数,则该值不能被任何提到的素数整除,并且小于或等于原始数。 它本身必须是质数。 所有可能的因素 <= S 已经被排除,因此任何假设因素 > S(除以它的结果是什么?另一个已经测试过的小于 S 的素数)。

从设计的角度来看,我还将解决如何在 OP 的代码中计算和存储素数。 因式分解 function 基本上是这样写的。

unsigned long long int MAX_LIMIT = 9999999999999;

std::vector<unsigned long long int> intFactorisation (unsigned long long int num)
{
    static std::vector<unsigned long long int> primes;
//  ^^^^^^                                           ^
    if (primes.empty())
    {
        // generate prime numbers up to MAX_LIMIT using sieve method
    }
    // Use the primes...
}     

static 向量可以使用单独的 function 进行初始化并声明为const ,但考虑到与分解 function 的密切关系,最好将这些数据和功能包装到 class 中,负责正确分配和初始化资源。

由于在语言中引入了 lambda,我们可以避免大部分与普通函子 class 关联的样板,因此分解 function 可以构造为由以下返回的有状态 lambda:

auto make_factorizer(uint64_t max_value)
{
    uint64_t sqrt_of_max = std::ceil(std::sqrt(max_value));
    // Assuming to have a function returning a vector of primes.
    // The returned lambda will accept the number to be factorized and
    // a reference to a vector where the factors will be stored
    return [primes = all_primes_up_to(sqrt_of_max)](uint64_t number,
                                                    std::vector<uint64_t>& factors)
    {
        uint64_t n{number};
        factors.clear();
        // Test against all the known primes, in ascending order
        for (auto prime : primes)
        {
            // You can stop earlier, if prime >= sqrt(n)
            if (n / prime <= prime)
                break;
            // Keep "consuming" the number with the same prime,
            // a factor can have a multiplicity greater than one.
            while (n % prime == 0)
            {
                n /= prime;
                factors.push_back(prime);
            }
        }
        // If n == 1, it has already found and stored all the factors. 
        // If it has run out of primes or breaked out from the loop,
        // either what remains is a prime or number was <= 1. 
        if (n != 1  ||  n == number)
        {
            factors.push_back(n);
        }
    };
}

这里测试了一个实时实现。

更简单的解决方案可能是即时找到所有质因数,而不是一开始就列出所有质数并检查它是否是给定数的因数。

这里是 function 在不分配大 memory 的情况下找到因子,

std::vector<unsigned long long int> intFactorisation(unsigned long long int num) {
    std::vector<unsigned long long int> answers{};
    unsigned long long int Current_Prime = 2;
    bool  found;
    while (num!=1 && num!=0)
    {
        //push all the factor repeatedly until it is not divisible
        // for input 12 push 2,2 and exit
        while (num % Current_Prime == 0) {
            answers.push_back(Current_Prime);
            num /= Current_Prime;
        }
        //find Next Prime factor 
        while (Current_Prime <= num) {
            Current_Prime++;
            found = true;
            for (unsigned long long int x = 2; x*x < Current_Prime; x++)
            {
                if (Current_Prime%x == 0) {
                    found = false;
                    break;
                }
            }

            if (found == true)
                break;
        }
    }

    return answers;
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM