我正在Linux中编写一些C ++代码,我已经声明了一些像这样的2D数组:
double x[5000][500], y[5000][500], z[5000][500];
编译期间没有错误。当我执行它时说“分段错误”。
Wen我将数组的大小从5000减少到50,程序运行正常。我怎样才能保护自己免受这个问题的影响?
答案 0 :(得分:64)
如果你的程序看起来像这样......
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。
速度方式是使用Blitz++。
答案 1 :(得分:16)
这些数组在堆栈中。堆栈的大小非常有限。你可能遇到了...堆栈溢出:)
如果你想避免这种情况,你需要将它们放在免费商店:
double* x =new double[5000*5000];
但你最好开始使用标准容器的好习惯,这些容器会为你包装所有这些:
std::vector< std::vector<int> > x( std::vector<int>(500), 5000 );
另外:即使堆栈适合数组,你仍然需要空间来放置它们的帧。
答案 2 :(得分:5)
您可能想尝试使用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]);
实际的大内存块将在堆上分配,并在必要时自动解除分配。
答案 3 :(得分:3)
您的声明应出现在任何程序或方法之外的顶层。
到目前为止在C或C ++代码中诊断段错误的最简单方法是使用valgrind 。如果您的某个阵列出现故障,那么valgrind将精确确定其位置和方式。如果故障在别处,它也会告诉你。
valgrind可用于任何x86二进制文件,但如果使用gcc -g
进行编译,则会提供更多信息。
答案 4 :(得分:2)
关于总是使用vector的一个保留:据我所知,如果你走出数组的末尾,它只需要分配一个更大的数组并复制所有内容,当你真正打结时,这些内容可能会产生微妙而难以找到的错误使用固定大小的数组。至少对于一个真实的数组,如果你走到最后,你会发生段错误,使得错误更容易被捕获。
#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;
}
答案 5 :(得分:1)
在我看来,你有一个诚实的Spolsky堆栈溢出!
尝试使用gcc的-fstack-check选项编译程序。如果您的数组太大而无法在堆栈上分配,那么您将获得StorageError异常。
我认为这是一个不错的选择,因为5000 * 500 * 3双打(每个8字节)大约60兆 - 没有平台有足够的堆栈。你必须在堆上分配你的大数组。
答案 6 :(得分:0)
以前的解决方案是执行
ulimit -s stack_area
扩展最大堆栈。