大向量“分段错误”错误

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() - 1jump 可能是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;

【讨论】:

500 std::vector&lt;int&gt; 实例实际上不应超过大多数环境的堆栈存储限制。 同意!我的观点是,考虑到 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&lt;int&gt; 实例动态分配内存。

要实现这一点,只需像这样使用嵌套的std::vetcor

 std::vector<std::vector<int>> primes(SIZE);

改为。

但要直截了当,我严重怀疑您是否需要多个 SIZE 向量实例来存储找到的所有质数,但只需一个初始化如下:

 std::vector<int> primes(SIZE);

【讨论】:

他甚至只使用其中之一。我认为他的意思是单个向量,但认为他需要使用 [SIZE] 预先分配其大小。 @LightnessRacesinOrbit 是的,这就是为什么我一直在编辑 “你认为需要”。答案很好地解释了,实际看似正常工作(如上所述)代码出了什么问题。

以上是关于大向量“分段错误”错误的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中使用向量时出现分段错误

向量:: 擦除分段错误

带有向量和字符串的 C++ 分段错误

对向量使用 Push Back 功能时的分段错误

对检索到的向量进行操作时出现分段错误

在 C++ 中比较来自向量的字符串时出现分段错误