2012-10-06 10 views
29

私はいくつかのプログラムに問題がありますが、セグメンテーションフォルトについてはよく理解していないので、私が知っている唯一のことはおそらく私がいくつかのメモリにアクセスしようとしていることですすべきではない。問題は、私のコードを見て、私が間違っていることを理解していないということです。セグメンテーションフォールト:11

#include<stdio.h> 
#include<math.h> 
#include<stdlib.h> 

#define lambda 2.0 
#define g  1.0 
#define Lx  100 
#define F0  1.0 
#define Tf  10 
#define h  0.1 
#define e  0.00001 

FILE *file; 

double F[1000][1000000]; 

void Inicio(double D[1000][1000000]) { 
int i; 
for (i=399; i<600; i++) { 
    D[i][0]=F0; 
} 
} 

void Iteration (double A[1000][1000000]) { 
long int i,k; 
for (i=1; i<1000000; i++) { 
    A[0][i]= A[0][i-1] + e/(h*h*h*h)*g*g*(A[2][i-1] - 4.0*A[1][i-1] + 6.0*A[0][i-1]-4.0*A[998][i-1] + A[997][i-1]) + 2.0*g*e/(h*h)*(A[1][i-1] - 2*A[0][i-1] + A[998][i-1]) + e*A[0][i-1]*(lambda-A[0][i-1]*A[0][i-1]); 
    A[1][i]= A[1][i-1] + e/(h*h*h*h)*g*g*(A[3][i-1] - 4.0*A[2][i-1] + 6.0*A[1][i-1]-4.0*A[0][i-1] + A[998][i-1]) + 2.0*g*e/(h*h)*(A[2][i-1] - 2*A[1][i-1] + A[0][i-1]) + e*A[1][i-1]*(lambda-A[1][i-1]*A[1][i-1]); 
    for (k=2; k<997; k++) { 
     A[k][i]= A[k][i-1] + e/(h*h*h*h)*g*g*(A[k+2][i-1] - 4.0*A[k+1][i-1] + 6.0*A[k][i-1]-4.0*A[k-1][i-1] + A[k-2][i-1]) + 2.0*g*e/(h*h)*(A[k+1][i-1] - 2*A[k][i-1] + A[k-1][i-1]) + e*A[k][i-1]*(lambda-A[k][i-1]*A[k][i-1]); 
    } 
    A[997][i] = A[997][i-1] + e/(h*h*h*h)*g*g*(A[0][i-1] - 4*A[998][i-1] + 6*A[997][i-1] - 4*A[996][i-1] + A[995][i-1]) + 2.0*g*e/(h*h)*(A[998][i-1] - 2*A[997][i-1] + A[996][i-1]) + e*A[997][i-1]*(lambda-A[997][i-1]*A[997][i-1]); 
    A[998][i] = A[998][i-1] + e/(h*h*h*h)*g*g*(A[1][i-1] - 4*A[0][i-1] + 6*A[998][i-1] - 4*A[997][i-1] + A[996][i-1]) + 2.0*g*e/(h*h)*(A[0][i-1] - 2*A[998][i-1] + A[997][i-1]) + e*A[998][i-1]*(lambda-A[998][i-1]*A[998][i-1]); 
    A[999][i]=A[0][i]; 
} 
} 

main() { 
long int i,j; 
Inicio(F); 
Iteration(F); 
file = fopen("P1.txt","wt"); 
for (i=0; i<1000000; i++) { 
    for (j=0; j<1000; j++) { 
     fprintf(file,"%lf \t %.4f \t %lf\n", 1.0*j/10.0, 1.0*i, F[j][i]); 
    } 
} 
fclose(file); 
} 

お時間をいただきありがとうございます。

+0

どの時点でセグメンテーションが発生しますか? –

+1

^Valgrindを使用して、segfaultが発生する行番号を取得してください。 1行に絞り込んだら一般的にはかなり明白です。そうでない場合は、それをどの行に投稿すればよいでしょうか? –

+3

あなたのコードを見て、まずあなたのコンパイラはセグメンテーションフォールトになっているに違いありません... – perilbrain

答えて

62

この宣言:

double F[1000][1000000]; 

は、一般的なx86システム上の8×1000 * 1000000バイトを占有します。これは約7.45 GBです。コードを実行しようとすると、システムのメモリが不足している可能性があり、結果としてセグメンテーションフォルトが発生します。

+0

ありがとうございました。 – Ariaramnes

1

どのシステムを実行していますか?何らかのデバッガ(gdb、Visual Studioのデバッガなど)にアクセスできますか?

これは、プログラムがクラッシュするコード行のような貴重な情報を提供します...また、メモリの量が制限される可能性があります。

また、数値制限を名前付きの定義に置き換えることをお勧めしますか?このように

:あなたは配列の次元の限界を参照したい時はいつでも

#define DIM1_SZ 1000 
#define DIM2_SZ 1000000 

たものを使用してください。入力ミスを避けるのに役立ちます。

0

valgrindのプログラムをefenceにリンクして実行してください。これは、ポインタがどこから参照解除されているかを示し、あなたが教えてくれたすべてのエラーを修正すれば問題を解決する可能性が非常に高いです。

29

お使いのアレイは、約8 GBのメモリ(1,000 x 1,000,000 x sizeof(double)バイト)を占有しています。それはあなたの問題の要因かもしれません。それはスタック変数ではなくグローバル変数ですので、あなたはOKかもしれませんが、ここでは制限を押しています。

多くのデータをファイルに書き込むにはしばらく時間がかかるでしょう。

ファイルが正常に開かれたことを確認しません。これも問題の原因となる可能性があります(失敗した場合は、セグメンテーションフォールトが発生する可能性があります)。

実際には1,000と1,000,000の名前付き定数をいくつか導入する必要があります。彼らは何を表していますか?

また、計算を行う関数を記述する必要があります。 C99以降(またはC++)でinline関数を使用できます。コードの繰り返しは、見苦しいです。 (あなたがargcargvを使用していないとき、引数リストのための好ましいvoidをして)

また、明示的な戻り値の型と、main()用C99表記を使用する必要があります。

int main(void) 

をアイドル好奇心からコードのコピーをとり、1000からROWSのすべての出現をすべて1000000からCOLSに変更し、を作成しました(これにより、問題のサイズは100倍に縮小されました)。私はいくつかのマイナーチェンジを行い、好みのコンパイルオプション(コンパイルオプションの前にstaticとメイン配列; filemainにローカルになります;エラーはfopen()などをチェックします)の下できれいにコンパイルします。

次に、2番目のコピーを作成し、繰り返し計算を行うためのインライン関数を作成しました(2番目は添え字計算を行います)。これは、怪物のような表現が一度だけ書き出されることを意味します。これは、一貫性を保証するために非常に望ましいものです。

#include <stdio.h> 

#define lambda 2.0 
#define g  1.0 
#define F0  1.0 
#define h  0.1 
#define e  0.00001 

enum { ROWS = 1000, COLS = 10000 }; 

static double F[ROWS][COLS]; 

static void Inicio(double D[ROWS][COLS]) 
{ 
    for (int i = 399; i < 600; i++) // Magic numbers!! 
     D[i][0] = F0; 
} 

enum { R = ROWS - 1 }; 

static inline int ko(int k, int n) 
{ 
    int rv = k + n; 
    if (rv >= R) 
     rv -= R; 
    else if (rv < 0) 
     rv += R; 
    return(rv); 
} 

static inline void calculate_value(int i, int k, double A[ROWS][COLS]) 
{ 
    int ks2 = ko(k, -2); 
    int ks1 = ko(k, -1); 
    int kp1 = ko(k, +1); 
    int kp2 = ko(k, +2); 

    A[k][i] = A[k][i-1] 
      + e/(h*h*h*h) * g*g * (A[kp2][i-1] - 4.0*A[kp1][i-1] + 6.0*A[k][i-1] - 4.0*A[ks1][i-1] + A[ks2][i-1]) 
      + 2.0*g*e/(h*h) * (A[kp1][i-1] - 2*A[k][i-1] + A[ks1][i-1]) 
      + e * A[k][i-1] * (lambda - A[k][i-1] * A[k][i-1]); 
} 

static void Iteration(double A[ROWS][COLS]) 
{ 
    for (int i = 1; i < COLS; i++) 
    { 
     for (int k = 0; k < R; k++) 
      calculate_value(i, k, A); 
     A[999][i] = A[0][i]; 
    } 
} 

int main(void) 
{ 
    FILE *file = fopen("P2.txt","wt"); 
    if (file == 0) 
     return(1); 
    Inicio(F); 
    Iteration(F); 
    for (int i = 0; i < COLS; i++) 
    { 
     for (int j = 0; j < ROWS; j++) 
     { 
      fprintf(file,"%lf \t %.4f \t %lf\n", 1.0*j/10.0, 1.0*i, F[j][i]); 
     } 
    } 
    fclose(file); 
    return(0); 
} 

このプログラムはP2.txt代わりのP1.txtに書き込みます。私は両方のプログラムを実行し、出力ファイルを比較しました。出力は同じでした。ほとんどのアイドル状態のマシン(MacBook Pro、2.3 GHz Intel Core i7、16 GiB 1333 MHz RAM、Mac OS X 10.7.5、GCC 4.7.1)でプログラムを実行したとき、合理的には完全にタイミングが得られました。

Original Modified 
6.334s  6.367s 
6.241s  6.231s 
6.315s  10.778s 
6.378s  6.320s 
6.388s  6.293s 
6.285s  6.268s 
6.387s  10.954s 
6.377s  6.227s 
8.888s  6.347s 
6.304s  6.286s 
6.258s  10.302s 
6.975s  6.260s 
6.663s  6.847s 
6.359s  6.313s 
6.344s  6.335s 
7.762s  6.533s 
6.310s  9.418s 
8.972s  6.370s 
6.383s  6.357s 

しかし、ほとんどすべての時間がディスクI/Oに費やされます。私は、データのちょうど非常に最後の行にディスクI/Oを削減し、その外側のI/O forループになった:

for (int i = COLS - 1; i < COLS; i++) 

タイミングが大幅に減少し、非常にはるかに一貫していた。

Original Modified 
0.168s  0.165s 
0.145s  0.165s 
0.165s  0.166s 
0.164s  0.163s 
0.151s  0.151s 
0.148s  0.153s 
0.152s  0.171s 
0.165s  0.165s 
0.173s  0.176s 
0.171s  0.165s 
0.151s  0.169s 

ghastly式を一度書いたコードを単純化することは非常に有益です。私は確かに元のものよりもそのプログラムを維持しなければならないはずです。

関連する問題