由于数组大小的分段错误?

时间:2016-11-30 14:07:12

标签: c++

我一直在做一个非常简单的有限差分代码来解决一维对流方程。 它似乎工作得很好,但如果我增加我正在使用的数组的大小我得到分段错误错误。当我缩短时间步长或增加时间间隔时会发生这种情况。 代码是

#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;
  }

  }

我认为这不是走出循环中数组边界的问题,因为代码适用于“小”数组。 我想我必须对数组处理做错了,但我找不到错误。

4 个答案:

答案 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 + 1n + 1处的索引,这意味着,您不仅仅是数组末尾的两个步骤。

答案 2 :(得分:0)

在计算第二个时间步时,您引用f上的x=xit=ti+dt,这是在第一个时间步骤中未计算的,因为i从1开始运行。在另一个边界存在类似的问题。

您需要为所有x=xi指定x=xft的空间边界条件,并修复其他答案中记录的逐个错误。

为了澄清,对流方程需要为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()您正在访问fex向量越界,因此可以正确诊断问题(正如其他答案所做的那样)