2016-11-30 47 views
0

我一直在做一個非常簡單的有限差分代碼,它解決了一維對流方程。 它似乎工作得很好,但如果我增加我使用的數組的大小,我會得到一個分段錯誤錯誤。當我減少時間步或者增加時間間隔時會發生這種情況。 該代碼是由於數組大小而導致分割錯誤?

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

    } 

我認爲這不是循環中的數組邊界問題,因爲代碼適用於「小」數組。 我想我一定是做錯了數組處理,但我找不到錯誤。

+5

請注意,'f'和'ex'都是可變長度數組,並且在C++中不是標準的。 – NathanOliver

+0

假設你的編譯器有一個允許[可變長度數組]的擴展(https://en.wikipedia.org/wiki/Variable-length_array),發生崩潰時'nstep_x'和'nstep_t'的值是什麼?而且您知道頂級索引是'nstep_x - 1'(檢查你的循環條件)? –

+1

'n <= nstep_t':我打賭你想'n malat

回答

0

您的代碼有幾個問題。一個是你使用的變長陣列(VLA)是而不是標準C++。

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異常。

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向量超出界限,因此可以正確診斷問題(如其他答案已完成)。

+0

非常感謝,我非常感謝您的詳細評論。現在我意識到我的代碼有幾處錯誤。乾杯,毛羅 – Mauro

0

GDB將有助於看到它實際上崩潰,但:

f[i+1][n]i長大到nstep_x,但f[nstep_x] [nstep_t], 所以好像你要訪問f[nstep_x+1][n]f分配,但最大可以是f[nstep_x-1][n]

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處的索引,這意味着,您不是數組末尾的兩個步驟。

0

當計算第二時間步,你指的是fx=xit=ti+dt這是不是在第一時間步長計算,因爲i運行從1有一個在其他邊界類似的問題。

您需要爲所有t指定x=xix=xf的空間邊界條件,以及修復其他答案中提到的偏差錯誤。

爲了澄清,對流方程需要指定邊界條件爲f(x=xi,t)f(x=xf, t)。在「絕緣」邊界的情況下,這通常是恆定的或規定的流量,但存在其他類型。

相關問題