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