大的二维arrays给出了分段错误

我在Linux中写了一些C ++代码,我已经声明了一些2D数组,如下所示:

double x[5000][500], y[5000][500], z[5000][500]; 

编译期间没有错误。 当我执行它说“分段错误”。

温我把数组的大小从5000减less到50,程序运行良好。 我怎样才能保护自己免受这个问题?

如果你的程序看起来像这样…

 int main(int, char **) { double x[5000][500],y[5000][500],z[5000][500]; // ... return 0; } 

…那么你是溢出堆栈。 解决这个问题的最快方法是添加static这个词。

 int main(int, char **) { static double x[5000][500],y[5000][500],z[5000][500]; // ... return 0; } 

解决这个问题的第二个最快的方法是将声明移出函数:

 double x[5000][500],y[5000][500],z[5000][500]; int main(int, char **) { // ... return 0; } 

解决这个问题的第三个最快的方法是在堆上分配内存:

 int main(int, char **) { double **x = new double*[5000]; double **y = new double*[5000]; double **z = new double*[5000]; for (size_t i = 0; i < 5000; i++) { x[i] = new double[500]; y[i] = new double[500]; z[i] = new double[500]; } // ... for (size_t i = 5000; i > 0; ) { delete[] z[--i]; delete[] y[i]; delete[] x[i]; } delete[] z; delete[] y; delete[] x; return 0; } 

第四种最快的方法是使用std :: vector在堆上分配它们。 你的文件中的行少了,而编译单元中有更多的行,你必须为你的派生向量类型考虑一个有意义的名字,或者把它们放到一个匿名的名字空间中,这样它们就不会污染全局名字空间:

 #include <vector> using std::vector namespace { struct Y : public vector<double> { Y() : vector<double>(500) {} }; struct XY : public vector<Y> { XY() : vector<Y>(5000) {} } ; } int main(int, char **) { XY x, y, z; // ... return 0; } 

第五种最快的方法是在堆上分配它们,但是使用模板,因此维度与对象没有太大的距离:

 include <vector> using namespace std; namespace { template <size_t N> struct Y : public vector<double> { Y() : vector<double>(N) {} }; template <size_t N1, size_t N2> struct XY : public vector< Y<N2> > { XY() : vector< Y<N2> > (N1) {} } ; } int main(int, char **) { XY<5000,500> x, y, z; XY<500,50> mini_x, mini_y, mini_z; // ... return 0; } 

性能最高的方法是将二维数组分配为一维数组,然后使用索引算术。

以上所有都假设你有一些理由,一个好的或者一个差的理由,因为你想要创建你自己的多维数组机制。 如果你没有理由,并期望再次使用多维数组,则强烈建议安装一个库:

  • 与STL搭配的方式就是使用Boost Multidimensional Array 。

  • 速度方法是使用flash ++ 。

这些数组在堆栈上。 堆栈的大小相当有限。 你可能会遇到一个堆栈溢出:)

如果你想避免这种情况,你需要把它们放在免费的商店:

 double* x =new double[5000*5000]; 

但是你最好开始使用标准容器的好习惯,它将所有这些包装给你:

 std::vector< std::vector<int> > x( std::vector<int>(500), 5000 ); 

另外:即使栈适合阵列,你仍然需要空间放置框架。

你可能想尝试使用Boost.Multi_array

 typedef boost::multi_array<double, 2> Double2d; Double2d x(boost::extents[5000][500]); Double2d y(boost::extents[5000][500]); Double2d z(boost::extents[5000][500]); 

实际的大内存块将被分配到堆上,并在必要时自动释放。

您的声明应该出现在任何程序或方法之外的顶层。

到目前为止在C或C ++代码中诊断段错误的最简单方法使用valgrind 。 如果你的一个阵列有问题,valgrind会精确地指出在哪里以及如何。 如果错误在别处,它也会告诉你。

valgrind可以在任何x86二进制文件上使用,但如果使用gcc -g编译,将会提供更多的信息。

关于总是使用向量的一个保留:据我了解,如果你离开数组的末尾,它只是分配一个更大的数组,并复制一切可能会创建微妙,很难找到错误,当你真的要搭配工作一个固定大小的数组。 至少在一个真正的数组中,如果你走到最后,容易捕捉到错误,那么你将会错误地分段。

 #include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { typedef double (*array5k_t)[5000]; array5k_t array5k = calloc(5000, sizeof(double)*5000); // should generate segfault error array5k[5000][5001] = 10; return 0; } 

在我看来,你有一个诚实的Spolsky堆栈溢出!

尝试用gcc的-fstack-check选项编译你的程序。 如果你的数组太大而无法在堆栈上分配,你会得到一个StorageError异常。

不过,我认为这是一个很好的选择,因为5000 * 500 * 3双打(每个8字节)达到60万左右 – 没有哪个平台有足够的堆栈。 你将不得不在堆上分配你的大数组。

以前的另一个解决方案是执行一个

 ulimit -s stack_area 

扩大最大的堆栈。