由于阵列大小而导致分段错误?
Segmentation fault because of the array size?
我一直在做一个非常简单的有限差分代码来解决一维对流方程。 它似乎工作得很好,但是如果我增加正在使用的数组的大小,就会出现分段错误。当我减少时间步长或增加时间间隔时,就会发生这种情况。 代码是
#include <math.h>
#include <iostream>
#include <fstream>
#include <stdio.h>
#include <cmath>
using namespace std;
int main(){
double xi = 0.0;
double xf = 10.0;
double ti = 0.0;
double tf = 1.0;
时间间隔,如果等于 1,则代码工作正常。
double x,t;
double dt = 0.1;
double dx = 0.1;
int nstep_x = (xf - xi)/dx;
int nstep_t = (tf - ti)/dt;
double f[nstep_x][nstep_t];
double ex[nstep_x][nstep_t];
// Parameters
const double v = 0.05;
const double D = 0.0001;
const double pi = 3.141592654;
ofstream salida;
salida.open("out");
for (int i = 0 ; i <= nstep_x; i++){
x = xi + dx*i;
f[i][0] = 0.5*sin(pi*x); //Initial conditions
salida << x << " " << 0 << " " << f[i][0] << endl;
}
salida << endl;
for (int n = 0; n <= nstep_t ; n++){
t = ti + n*dt;
for (int i = 1; i <= nstep_x; i++){
x = xi + dx*i;
f[i][n+1] = f[i][n] - ((v*dt)/(2*dx))*(f[i+1][n] - f[i-1][n]); //CONV|SOC
ex[i][n] = 0.5*sin(pi*x - v*t);
salida << x << " " << t << " " << ex[i][n] << " " << f[i][n] << endl;
}
salida << endl;
salida << endl;
}
}
我认为这不是在循环中超出数组边界的问题,因为代码适用于"小"数组。 我想我一定是数组处理出了问题,但我找不到错误。
您的代码有几个问题。 一个是你正在使用不是标准C++的可变长度数组(VLA)。
double f[nstep_x][nstep_t];
double ex[nstep_x][nstep_t];
这C++无效,因为数组的大小必须在编译时而不是运行时知道。
快速的解决方案是使用std::vector<std::vector<double>>
:
#include <vector>
//...
std::vector<std::vector<double>> f(nstep_x, std::vector<double>(nstep_t));
std::vector<std::vector<double>> ex = f; // use copy constructor to easily create a copy
上面的代码基本上做了你最初做的事情,但有几个优点:
1) 代码现在是标准C++,因为它使用标准C++容器类std::vector
.
2)如果nstep_x
和/或nstep_t
是大值,您不会遇到堆栈空间问题,因为std::vector
会获得内存来存储堆中的项目。
3) 如果怀疑您越界访问矢量,您可以使用std::vector::at()
检查边界条件。 如果您使用的是VLA(或一般的数组),则没有此测试。
在尝试查找错误时,第 3 项变得很重要。
如果我们采用您的代码,将其更改为 使用std::vector
,我们看到"小数组"存在问题,与您认为不是问题的情况背道而驰。 如果我们看一下这段代码:
for (int i = 0 ; i <= nstep_x; i++)
{
x = xi + dx*i;
f.at(i).at(0) = 0.5*sin(pi*x); // exception is thrown here
}
我们看到存在越界条件。 这是通过使用vector::at()
而不是[ ]
来访问矢量中的元素来检测的。 在分配f[i][0]
的行处引发std::out_of_range
异常。
下面是显示此错误的实时示例。
你如何解决这个问题? 只是不要通过更改循环来越界:
for (int i = 0 ; i < nstep_x; i++)
在其他循环中也存在边界条件问题:
for (int n = 0; n <= nstep_t ; n++)
{
t = ti + n*dt;
for (int i = 1; i <= nstep_x; i++)
{
x = xi + dx*i;
f.at(i).at(n+1) = f[i][n] - ((v*dt)/(2*dx))*(f.at(i+1).at(n) - f[i-1][n]);
ex.at(i)(n) = 0.5*sin(pi*x - v*t);
}
}
您将看到使用at()
您正在越界访问f
和ex
向量,因此可以正确诊断问题(就像其他答案所做的那样)。
gdb 将有助于查看它实际崩溃的位置,但是:
f[i+1][n]
和i
增长到nstep_x
,但f
被分配为f[nstep_x]
[nstep_t], 所以看起来你会访问f[nstep_x+1][n]
,但你能做的最多是f[nstep_x-1][n]
。
如注释中所述,原因不是数组大小,而是 for 循环
for (int i = 0 ; i <= nstep_x; i++) {
// ...
f[i][0] = 0.5*sin(pi*x);
}
这是一个典型的一次性错误,超出了数组的末尾。正确的方法是
for (int i = 0 ; i < nstep_x; i++) {
// ...
}
注意<
vs<=
.
for (int n = 0; n <= nstep_t ; n++) {
for (int i = 1; i <= nstep_x; i++) {
// ...
f[i][n+1] = f[i][n] - ((v*dt)/(2*dx))*(f[i+1][n] - f[i-1][n]);
}
}
在这里,您也有<=
而不是<
.此外,您分别在i + 1
和n + 1
处访问索引,这意味着您不是在数组末尾的一步,而是两步。
在计算第二个时间步长时,您指的是在x=xi
处f
,t=ti+dt
在第一个时间步长中没有计算,因为i
从 1 开始运行。在另一个边界也存在类似的问题。
您需要为所有t
指定x=xi
和x=xf
的空间边界条件,并修复其他答案中指出的逐一错误。
为了澄清,对流方程需要为f(x=xi,t)
和f(x=xf, t)
指定边界条件。在"绝缘"边界的情况下,这通常是恒定或规定的流速,但存在其他类型。
- 在某些循环内使用vector.push_back时出现分段错误
- 为什么在运行时没有向我们提供有关分段错误的更多信息?
- 如何解决gcc编译器优化导致的centos双编译器设置中的分段错误
- 当我的阵列太大时出现分段错误
- 分段错误当我试图运行程序时出错
- 在c++中初始化矩阵时出现分段错误(核心转储)
- 尝试使用集合函数时出现分段错误
- 我无法缩小此分段错误的原因
- g++的分段错误(在NaN上使用to_string两次时)
- 我是如何在这段代码中出现分段错误的
- 创建结构的数组时遇到分段错误
- 在c++中键入向量中的所有值后,得到分段错误(核心转储)
- 在 c++ 中实现 Trie 时出现分段错误
- 为什么 fstream 在打开带有格式的文件时会导致分段错误?
- 为什么我遇到分段错误?
- 动态类的分段错误(家庭作业问题)
- 分段错误 - 读取初始化指针的数组
- 如何摆脱C ++中的分段错误错误?
- 使用 CTYPE 时出现分段错误
- 为什么代码给出分段错误?