簡體   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