我在Linux中编写了一些C++代码,其中我声明了一些2D数组,如下所示:
double x[5000][500], y[5000][500], z[5000][500];
在编译过程中没有错误。当我执行它时,它说“分段错误”。当我把数组的大小从5000减到50时,程序运行正常。我如何保护自己不受这个问题的影响?
hpcdzsge1#
如果你的程序看起来像这样...
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; }
性能最好的方法是将二维数组作为一维数组分配,然后使用索引算法。以上所有的假设都是假设你有一些理由,不管是好是坏,来创建你自己的多维数组机制。如果你没有理由,并且希望再次使用多维数组,强烈考虑安装一个库:
y53ybaqx2#
这些数组在堆栈上。堆栈的大小相当有限。您可能会遇到...堆栈溢出:)如果你想避免这种情况,你需要把它们放在免费商店:
double* x =new double[5000*5000];
但是您最好开始养成使用标准容器的好习惯,它会为您 Package 所有这些内容:
std::vector< std::vector<int> > x( std::vector<int>(500), 5000 );
另外:即使堆栈适合数组,您仍然需要为函数提供空间,以便将它们的框架放在堆栈上。
0ejtzxu13#
您可能希望尝试使用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]);
实际的大内存块将在堆上分配,并在必要时自动释放。
niknxzdl4#
您的声明应该出现在顶层,在任何过程或方法之外.到目前为止,在C或C++代码中诊断segfault最简单的方法是使用valgrind。如果你的一个数组出现了错误,valgrind会精确地指出错误的位置和方式。如果错误发生在其他地方,它也会告诉你。valgrind可以在任何x86二进制文件上使用,但如果使用gcc -g编译,将给予更多信息。
gcc -g
ifsvaxew5#
关于始终使用向量的一个保留意见是:据我所知,如果你走到数组的末尾,它只会分配一个更大的数组,并复制所有的内容,当你真正使用固定大小的数组时,这可能会产生微妙的、难以发现的错误。至少对于一个真正的数组,如果你走到末尾,你会出现segfault,从而使错误更容易捕捉。
#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; }
yquaqz186#
在我看来,你有一个诚实的Spolsky堆栈溢出!试着用gcc的-fstack-check选项编译你的程序,如果你的数组太大而不能在堆栈上分配,你会得到一个StorageError异常。我认为这是一个很好的选择,因为50005003个双精度数(每个8字节)大约有60兆--没有平台有足够的堆栈,你必须在堆上分配你的大数组。
1l5u6lss7#
前一个问题的另一个解决方案是执行
ulimit -s stack_area
以扩展最大堆栈。
zaq34kh68#
您可能想尝试使用Multi库来实现多维数组(C++17)。
#include<multi/array.hpp> #include<cassert> namespace multi = boost::multi; int main() { using Double2D = multi::array<double, 2>; Double2D X({5000, 500}, 999.0); Double2D Y({5000, 500}); Double2D Z({5000, 500}); assert( X.size() == 5000 ); auto [m, n] = X.extensions(); assert( m == 5000 ); assert( n == 500 ); Y = X; assert( Y[0][0] == 999.0 ); }
https://godbolt.org/z/rh5M463Y1类似于Boost.MultiArray库(另一个答案),在堆中分配内存而不是使用(溢出)堆栈。它提供了其他特性,如赋值和迭代。
8条答案
按热度按时间hpcdzsge1#
如果你的程序看起来像这样...
...那么堆栈就会溢出。解决这个问题的最快方法是添加单词 static。
第二快的解决方法是将声明移出函数:
第三种最快的解决方法是在堆上分配内存:
第四种最快的方法是使用std::vector在堆上分配它们,这样文件中的行数会更少,但编译单元中的行数会更多,而且你必须为派生的向量类型想出一个有意义的名称,或者将它们放入一个匿名的名称空间中,这样它们就不会污染全局名称空间:
第五种最快的方法是在堆上分配维度,但是使用模板,这样维度就不会离对象太远:
性能最好的方法是将二维数组作为一维数组分配,然后使用索引算法。
以上所有的假设都是假设你有一些理由,不管是好是坏,来创建你自己的多维数组机制。如果你没有理由,并且希望再次使用多维数组,强烈考虑安装一个库:
y53ybaqx2#
这些数组在堆栈上。堆栈的大小相当有限。您可能会遇到...堆栈溢出:)
如果你想避免这种情况,你需要把它们放在免费商店:
但是您最好开始养成使用标准容器的好习惯,它会为您 Package 所有这些内容:
另外:即使堆栈适合数组,您仍然需要为函数提供空间,以便将它们的框架放在堆栈上。
0ejtzxu13#
您可能希望尝试使用Boost.Multi_array
实际的大内存块将在堆上分配,并在必要时自动释放。
niknxzdl4#
您的声明应该出现在顶层,在任何过程或方法之外.
到目前为止,在C或C++代码中诊断segfault最简单的方法是使用valgrind。如果你的一个数组出现了错误,valgrind会精确地指出错误的位置和方式。如果错误发生在其他地方,它也会告诉你。
valgrind可以在任何x86二进制文件上使用,但如果使用
gcc -g
编译,将给予更多信息。ifsvaxew5#
关于始终使用向量的一个保留意见是:据我所知,如果你走到数组的末尾,它只会分配一个更大的数组,并复制所有的内容,当你真正使用固定大小的数组时,这可能会产生微妙的、难以发现的错误。至少对于一个真正的数组,如果你走到末尾,你会出现segfault,从而使错误更容易捕捉。
yquaqz186#
在我看来,你有一个诚实的Spolsky堆栈溢出!
试着用gcc的-fstack-check选项编译你的程序,如果你的数组太大而不能在堆栈上分配,你会得到一个StorageError异常。
我认为这是一个很好的选择,因为50005003个双精度数(每个8字节)大约有60兆--没有平台有足够的堆栈,你必须在堆上分配你的大数组。
1l5u6lss7#
前一个问题的另一个解决方案是执行
以扩展最大堆栈。
zaq34kh68#
您可能想尝试使用Multi库来实现多维数组(C++17)。
https://godbolt.org/z/rh5M463Y1
类似于Boost.MultiArray库(另一个答案),在堆中分配内存而不是使用(溢出)堆栈。它提供了其他特性,如赋值和迭代。