我一直在做一个非常简单的有限差分代码来解决一维对流方程。 它似乎工作得很好,但如果我增加我正在使用的数组的大小我得到分段错误错误。当我缩短时间步长或增加时间间隔时会发生这种情况。 代码是
#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;
}
}
我认为这不是走出循环中数组边界的问题,因为代码适用于“小”数组。 我想我必须对数组处理做错了,但我找不到错误。
答案 0 :(得分:0)
gdb有助于查看它实际崩溃的位置,但是:
f[i+1][n]
和i
长到nstep_x
,但f
被分配为f[nstep_x]
[nstep_t],
因此,您似乎正在访问f[nstep_x+1][n]
,但您可以使用f[nstep_x-1][n]
。{/ p>
答案 1 :(得分:0)
如评论中所述,原因不是数组大小,而是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
处的索引,这意味着,您不仅仅是数组末尾的两个步骤。
答案 2 :(得分:0)
在计算第二个时间步时,您引用f
上的x=xi
和t=ti+dt
,这是在第一个时间步骤中未计算的,因为i
从1开始运行。在另一个边界存在类似的问题。
您需要为所有x=xi
指定x=xf
和t
的空间边界条件,并修复其他答案中记录的逐个错误。
为了澄清,对流方程需要为f(x=xi,t)
和f(x=xf, t)
指定边界条件。在绝缘材料的情况下,这通常是恒定的或规定的流速。边界,但存在其他类型。
答案 3 :(得分:0)
您的代码存在多个问题。一个是您正在使用不标准C ++的可变长度数组(VLA&#39;)。
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
,我们会发现 是&#34;小数组&#34;的问题,与您认为的相反这不是问题。如果我们看一下这段代码:
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()
而不是[ ]
来检测向量中的元素。在std::out_of_range
被分配到的行中抛出f[i][0]
异常。
Here is a live example showing this error
你如何解决这个问题?只需改变循环就不会超出界限:
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
向量越界,因此可以正确诊断问题(正如其他答案所做的那样)