大向量“分段错误”错误
Posted
技术标签:
【中文标题】大向量“分段错误”错误【英文标题】:Large vector "Segmentation fault" error 【发布时间】:2015-06-02 23:56:26 【问题描述】:我从其他人关于 SO 的问题和答案中收集了大量非常有用的信息,并且也适当地搜索了这个问题的答案。不幸的是,我还没有找到解决这个问题的方法。
以下函数生成素数列表:
void genPrimes (std::vector<int>* primesPtr, int upperBound = 10)
std::ofstream log;
log.open("log.txt");
std::vector<int>& primesRef = *primesPtr;
// Populate primes with non-neg reals
for (int i = 2; i <= upperBound; i++)
primesRef.push_back(i);
log << "Generated reals successfully." << std::endl;
log << primesRef.size() << std::endl;
// Eratosthenes sieve to remove non-primes
for (int i = 0; i < primesRef.size(); i++)
if (primesRef[i] == 0) continue;
int jumpStart = primesRef[i];
for (int jump = jumpStart; jump < primesRef.size(); jump += jumpStart)
if (primesRef[i+jump] == 0) continue;
primesRef[i+jump] = 0;
log << "Executed Eratosthenes Sieve successfully.\n";
for (int i = 0; i < primesRef.size(); i++)
if (primesRef[i] == 0)
primesRef.erase(primesRef.begin() + i);
i--;
log << "Cleaned list.\n";
log.close();
被调用:
const int SIZE = 500;
std::vector<int>* primes = new std::vector<int>[SIZE];
genPrimes(primes, SIZE);
此代码运行良好。但是,当我将 SIZE 的值更改为更大的数字(例如 500000)时,编译器会返回“分段错误”。我对向量不够熟悉,无法理解这个问题。非常感谢任何帮助。
【问题讨论】:
问题的根本形式是您没有足够的内存。您的可执行程序无法从操作系统获得足够的内存。 除了#1:为什么genPrimes
的第一个参数是指针而不是引用?除了#2:为什么primes
是一个指针并且是动态分配的,而不仅仅是一个局部变量? (除了#3:如果你认为这些问题是相关的,那是你的错误)
【参考方案1】:
您正在访问primesRef[i + jump]
,其中i
可能是primesRef.size() - 1
,jump
可能是primesRef.size() - 1
,导致访问越界。
发生的限制为 500,只是您目前碰巧没有因越界访问而产生任何不良副作用。
还要注意,在这里使用vector
是一个糟糕的选择,因为每次擦除都必须移动内存中的所有以下条目。
【讨论】:
这正是导致我的分段错误的问题,非常感谢!我还将考虑另一个不使用向量或以不同方式处理向量的构建。【参考方案2】:你确定要这样做
new std::vector<int> [500];
而不是
new std::vector<int> (500);
在后一种情况下,您正在指定向量的大小,您可以通过名为“primes”的变量获得其位置。
在前者中,您为 500 个向量请求空间,每个向量的大小都是 STL 库所需的默认值。
这将类似于(在我的系统上:24*500 字节)。在后一种情况下,您要求的是 500 长度的向量(只有一个向量)。
编辑:看看用法 - 他只需要一个向量。
std::vector& primesRef = *primesPtr;
【讨论】:
500std::vector<int>
实例实际上不应超过大多数环境的堆栈存储限制。
同意!我的观点是,考虑到 primesPtr 的使用,提问者可能滥用了导致一堆向量而不是所需大小的向量的分配。按照他的例子,他正在分配 500000 个向量。
为什么new
还在呢?我很想对你的答案投反对票,因为在绝对没有正当理由这样做的情况下,new
仍然令人作呕。
对,我没有超出代码的范围,如果确实有任何用处将这个向量放在堆上的话。那,我们不能肯定地说。但是,这种意外分配显然是个问题。
我在堆上创建了它,因为我是一个新手,我想因为我会(稍后)将向量的大小更改为更大的,所以我希望它在堆上。现实是,我通过更改硬编码常量来更改大小,不需要堆。谢谢!【参考方案3】:
问题出在这里:
// Populate primes with non-neg reals
for (int i = 2; i <= upperBound; i++)
primesRef.push_back(i);
您的向量中只有 N-2 个元素被推回,但随后尝试访问 N-1 处的元素(i+jump)。它没有在 500 上失败的事实只是运气不好,被覆盖的内存不是灾难性的。
【讨论】:
【参考方案4】:此代码运行良好。但是,当我将 SIZE 的值更改为更大的数字(例如,500000)时,...
这可能会破坏您的堆栈,并分配给它。您需要为您认为需要的所有 std::vector<int>
实例动态分配内存。
要实现这一点,只需像这样使用嵌套的std::vetcor
。
std::vector<std::vector<int>> primes(SIZE);
改为。
但要直截了当,我严重怀疑您是否需要多个 SIZE
向量实例来存储找到的所有质数,但只需一个初始化如下:
std::vector<int> primes(SIZE);
【讨论】:
他甚至只使用其中之一。我认为他的意思是单个向量,但认为他需要使用[SIZE]
预先分配其大小。
@LightnessRacesinOrbit 是的,这就是为什么我一直在编辑 “你认为需要”。答案很好地解释了,实际看似正常工作(如上所述)代码出了什么问题。以上是关于大向量“分段错误”错误的主要内容,如果未能解决你的问题,请参考以下文章