[英]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.