使用向量时的分段错误

时间:2013-12-13 00:27:50

标签: c++ vector

我正在尝试从projecteuler.net http://projecteuler.net/problem=14

解决问题

这是问题所在:

为正整数集定义了以下迭代序列:

n→n / 2(n是偶数) n→3n + 1(n为奇数)

使用上面的规则并从13开始,我们生成以下序列:

13→40→20→10→5→16→8→4→2→1 可以看出,该序列(从13开始并在1结束)包含10个项。虽然尚未证实(Collat​​z问题),但据认为所有起始数字都以1结束。

哪个起始编号低于一百万,产生最长的链?

注意:一旦链条启动,条款允许超过一百万。

我首先使用递归解决方案,但经过100,000次左右的迭代后出现了分段错误。所以我做了一个迭代的解决方案,希望能解决问题。在同一点发生分段故障。我查看了堆栈跟踪,发现当一个值添加到我标记下面一行的向量时,问题就出现了。我以为矢量会自动调整大小,所以我真的很困惑这个问题。谢谢你的帮助。这是代码:

#include <iostream>
#include <cstdlib>
#include <vector>
using namespace std;
 int ITERATIONS=100000;

int main()
{
vector<int> maxArray;
vector<int> newArray;
int max_size = 0;
int n = 2;
int collatz = n;
while(n <= ITERATIONS){

#Stack trace error# 
newArray.push_back(collatz);
#Stack trace error#

if(collatz == 1){
++n;
if(newArray.size() > max_size){
maxArray.clear();
for(vector<int>::const_iterator i = newArray.begin(); i < newArray.end(); ++i){
maxArray.push_back(*i);
}
max_size = newArray.size();
}
newArray.clear();
collatz = n;
}
else if(collatz%2 == 0)
collatz = collatz/2;
else
collatz = 3*collatz+1;
}
for(vector<int>::const_iterator i = maxArray.begin(); i < maxArray.end(); ++i){
cout << *i << " "; 
}
cout << "\n" << max_size;
}

堆栈跟踪:

#0  0x00132416 in __kernel_vsyscall ()
#1  0x002641df in raise () from /lib/i386-linux-gnu/libc.so.6
#2  0x00267825 in abort () from /lib/i386-linux-gnu/libc.so.6 #3  0x001e013d in __gnu_cxx::__verbose_terminate_handler() ()  from /usr/lib/i386-linux-gnu/libstdc++.so.6
#4  0x001dded3 in ?? () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#5  0x001ddf0f in std::terminate() ()  from /usr/lib/i386-linux-gnu/libstdc++.so.6
#6  0x001de05e in __cxa_throw () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#7  0x001de67f in operator new(unsigned int) () from /usr/lib/i386-linux-gnu/libstdc++.so.6
#8  0x08049362 in __gnu_cxx::new_allocator<int>::allocate (this=0xbffff214, 
__n=536870912) at /usr/include/c++/4.6/ext/new_allocator.h:92
#9  0x0804923c in std::_Vector_base<int, std::allocator<int> >::_M_allocate (
this=0xbffff214, __n=536870912)   at /usr/include/c++/4.6/bits/stl_vector.h:150
#10 0x08048e7f in std::vector<int, std::allocator<int> >::_M_insert_aux (
this=0xbffff214, __position=..., __x=@0xbffff220: -91)
at /usr/include/c++/4.6/bits/vector.tcc:327
#11 0x08048bdd in std::vector<int, std::allocator<int> >::push_back (
this=0xbffff214, __x=@0xbffff220: -91)
at /usr/include/c++/4.6/bits/stl_vector.h:834
#12 0x08048897 in main () at iterativeCollatz.cpp:16

4 个答案:

答案 0 :(得分:2)

条件i < newArray.end()应为i != newArray.end()。当然,同样适用于i < maxArray.end()

答案 1 :(得分:2)

#6  0x001de05e in __cxa_throw () from /usr/lib/i386-linux-gnu/libstdc++.so.6

__cxa_throw的此调用表示正在抛出C ++异常。

#5  0x001ddf0f in std::terminate() ()  from /usr/lib/i386-linux-gnu/libstdc++.so.6

std::terminate函数立即退出应用程序。这可能是由于以下几个原因造成的:

  1. 异常被抛出在对象的析构函数中,同时抛出另一个异常。
  2. 该程序没有try ... catch处理程序。
  3. 在这种情况下,选项2最有可能。运行程序应该会导致类似:

    terminate called after throwing an instance of 'std::bad_alloc'
      what():  std::bad_alloc
    
    Program received signal SIGABRT, Aborted.
    

    这会为您提供异常消息(what输出)。

    #7  0x001de67f in operator new(unsigned int) () from /usr/lib/i386-linux-gnu/libstdc++.so.6
    

    此行表示在分配内存时触发了异常(很可能是std::bad_alloc,表示内存不足。

    因此,我会检查你没有分配内存不足的大型向量。

    注意:您可以通过编写类似以下内容来添加自己的try...catch处理程序:

    try
    {
        // Your code here.
    }
    catch (const std::exception &e)
    {
        std::cout << "Error: " << e.what() << std::endl;
    }
    

    vector实现只要不再有任何空间,就会增加向量的大小。这通常通过将空间加倍(2,4,8,16 ......)来完成。这将变得非常快,你有2个向量增长到适合100000个元素。另请注意,在生成向量时,需要保留旧数据以复制到新向量中。

    您可以使用reservemaxArray上的newArray方法在循环之前设置所需的大小。那就是:

    maxArray.reserve(ITERATIONS);
    newArray.reserve(ITERATIONS);
    

    这也将确保更清晰的性能,因为向量不必增加内部数据数组来添加新元素。

答案 2 :(得分:2)

我们做出以下观察:

  1. 单个最小的链仅由数字1组成。其长度为1。
  2. 长链只能通过预先 x形成 tail 链,从x/2开始(如果x是偶数)或3x+1(如果x是奇数)。长链的长度是1加上尾巴的长度。
  3. 一旦链条开始,条款就可以超过一百万。
  4. 解决此问题并非真正需要负数。
  5. 没有链长度为0.
  6. 我们得出以下结论:

    1. 从观察1和2中:一旦我们发现从x开始的链的长度,我们必须记住它。这避免了重新计算尾部的长度。此外,我们可以将链长解释为0(默认情况下构造一个std::size)为“此长度尚未计算”。
    2. 从观察3:对于任何x > 1000000,如果我们最终需要计算从x开始的链的长度,那么没有什么能保证我们对从{开始的每个链的长度感兴趣{1}} y。所以我们应该使用关联数据结构(例如x > y >= 1000000)而不是std::map来存储已记忆的长度:
    3. 从观察3和4:我们将使用尽可能大的无符号整数类型。如果不使用bignum库(例如GMP),我们想要的类型是std::vector
    4. 从观察5:我们可以使用链长度值0来表示“此链长尚未计算”。这是特别方便的,因为C ++的关联容器默认构造一个值,当使用std::uint64_t时容器中不存在的键,并且整数类型的默认构造值初始化为0。
    5. 为方便起见,使用C ++ 11构造编写的结果程序是这样的:

      operator []

答案 3 :(得分:0)

我已经测试了你的代码并且没有SIGSEGV,也许你应该提供更多的信息。

以下是我的建议:

vector类有一个名为capacity()的成员函数,也许你应该检查一下。