アプリ版:「スタンプのみでお礼する」機能のリリースについて

学生で流体力学の研究を行っています。
研究の一環でフリーの数値解析ソフトを使っているのですが、ポスト処理の機能が弱いので、自作してみようと思いC言語で書いてみました。実行したところ、何とか結果は得られるのですが、エラーが出てしまいます。原因を教えて頂けたら幸いです。

翼周りの圧力分布を計算しており、ある点での圧力が時間とともにどのように変化するのか知りたかったので、今回のプログラムを作成しました。
実行ディレクトリ内には各時刻(以下のプログラム内では t)のディレクトリが存在し、その中に圧力(p)のデータが存在しています。各時刻のある点の圧力を一つのファイルに出力したかったので以下のプログラムを作りました。
実行したところ、
*** glibc detected *** ./a.out: double free or corruption (out): 0x0896f008 ***
======= Memory map: =========
・・・
というエラーが出てしまします。glibc detectedは領域の二重解放を意味するらしいのですが、どこがおかしいのかわかりません。どなたか教えて頂けないでしょうか?
C言語はかじった程度の知識しかないので、ほかにも変な点などがありましたら指摘して欲しいです。ubuntu 10.4上で動かしています。


実行ディレクトリ内   [以下のプログラム 0.0001 0.0002 0.0003 0.0004 ]
0.0001内        [p u(速度) などなど]
0.0002内   [p u(速度) などなど]
・・・


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

/* ベクトルの入力 */
void input_vector2(double *b, double t,int i , FILE *fin, FILE *fout);
/* 行列の領域確保 */
double **dmatrix(int nr1, int nr2, int nl1, int nl2);
/* 行列の領域解放 */
void free_dmatrix(double **a, int nr1, int nr2, int nl1, int nl2);
/* ベクトル領域の確保 */
double *dvector(int i, int j);
/* ベクトル領域の解放 */
void free_dvector(double *a, int i);

int main(void)
{
FILE *fin, *fout;
double *x;
double t1,t2,dt,t;
int n,i;
char fn[5];/*圧力を指定するためのパス*/
t1 = 0.0001; /* 初期時刻 */
t2 = 0.0004; /* 終了時刻 */
dt = 0.0001; /*時間幅*/


n = 1 + (t2-t1)/dt; /* データ数 */

/* ベクトルの領域確保 */
x = dvector(1,n); /* x[1...n] */

/*書き込み用ファイルのオープン*/
if( (fout = fopen( "output_p.dat", "w")) == NULL )
{
printf("ファイルが作成できません : output_p.dat \n");
exit(1);
}

for( i = 0 ; i <= n ; i++)
{
t=t1+dt*i;

sprintf( fn,"./%5.4f/p",t);
/* ファイルのオープン */
if( (fin = fopen( fn , "r")) == NULL )
{
printf("ファイルが見つかりません : fn/p.dat \n");
printf("%s \n",fn);
exit(1);
}


input_vector2( x, t, i,fin, fout ); /* ベクトルxの入出力 */
fclose(fin); /* ファイルのクローズ */

}
fclose(fout); /* ファイルのクローズ */

/* 領域の解放 */
free_dvector( x, 1 );
return 0;
}


/* b[1...n]の入力 */
void input_vector2( double *b, double t,int i ,FILE *fin, FILE *fout)
{
double a;
fseek(fin,860,SEEK_SET);
fscanf(fin, "%lf", &b[i]);
fprintf(fout, "%5.4f\t",t);
fprintf(fout, "%5.2f\n", b[i]);


}

double **dmatrix(int nr1, int nr2, int nl1, int nl2)
{
int i, nrow, ncol;
double **a;

nrow = nr2 - nr1 + 1 ; /* 行の数 */
ncol = nl2 - nl1 + 1 ; /* 列の数 */

/* 行の確保 */
if ( ( a=(double **)malloc( nrow*sizeof(double *) ) ) == NULL )
{
printf("メモリが確保できません(行列a)\n");
exit(1);
}
a = a - nr1; /* 行をずらす */
/* 列の確保 */
for( i=nr1; i<=nr2; i++) a[i] = (double *)malloc(ncol*sizeof(double));
for( i=nr1; i<=nr2; i++) a[i] = a[i]-nl1; /* 列をずらす */

return(a);
}

void free_dmatrix(double **a, int nr1, int nr2, int nl1, int nl2)
{
int i;

/* メモリの解放 */
for ( i = nr1 ; i <= nr2 ; i++) free((void *)(a[i]+nl1));
free((void *)(a+nr1));
}


double *dvector(int i, int j) /* a[i]?a[i+j]の領域を確保 */
{
double *a;

if ( (a=(double *)malloc( ((j-i+1)*sizeof(double))) ) == NULL )
{
printf("メモリが確保できません(from dvector) \n");
exit(1);
}

return(a-i);
}

void free_dvector(double *a, int i)
{
free( (void *)(a + i) ); /* (void *)型へのキャストが必要 */
}

A 回答 (5件)

>実行ディレクトリ内には各時刻(以下のプログラム内では t)のディレクトリが存在し、その中に圧力(p)のデータが存在しています。



不具合が発生する状況が確認できないので、よくわかりません。
質問する場合は、問題が再現する状態をすべて提示してください。

とりあえずコードを見ましたが

free_dmatrixの
/* メモリの解放 */
for ( i = nr1 ; i <= nr2 ; i++) free((void *)(a[i]+nl1));
free((void *)(a+nr1)); ←ここ

って二重解放になりそうですよ。
    • good
    • 0
この回答へのお礼

素早い解答どうもありがとうございます。
「問題が再現する状態」とは何なのかよくわからないですが、
「実行ディレクトリ内には各時刻(以下のプログラム内では t)のディレクトリが存在し、その中に圧力(p)のデータが存在しています。」の一文がよくわからなかったということですか?これなら大丈夫ですか?舌足らずですいません。
「プログラムを実行するディレクトリ内には各時刻(0.0001~0.0004 プログラム中では変数tで表しています)のディレクトリが存在し、その中に圧力(p)のデータが存在しています。」

なぜそこが二重解放になるのでしょうか?

お礼日時:2011/10/05 21:16

>なぜそこが二重解放になるのでしょうか?



そのようなケースがありえるのかわかりませんが
nl1 が 0 のときには起こりえそうですよ。

余計なお世話なんでしょうが
dmatrix, free_dmatrix
は、無駄に難しい気がするので
リファクタリングした方がいいと思います。
    • good
    • 0

>>なぜそこが二重解放になるのでしょうか?



>そのようなケースがありえるのかわかりませんが
>nl1 が 0 のときには起こりえそうですよ。

すいません。勘違いでした。
なりませんね。

Valgrindで調べてみてはいかがでしょうか。
    • good
    • 0
この回答へのお礼

何度もありがとうございます。

私自身もfree_dmatrixなどはあまり分からずに使っているのですが、同じものを何度か使っていままでエラーがなかったのでたぶん問題はないだろうと思います。
既存の問題のないプログラムから変更した箇所はメイン関数の部分とinput_vectorだけなのでそのあたりのどこかがおかしいのだと思うんですが、わからないです。

Vargrindというデバックツール(?)があるんですね。
導入が私には難しそうなので、どうしようもなかったら使ってみようと思います。
ありがとうございました。

お礼日時:2011/10/05 23:03

char fn[5];/*圧力を指定するためのパス*/



sprintf( fn,"./%5.4f/p",t);

まずは、fn のバッファの長さを適切にしてみては?
(最後のnull文字分も忘れずに!)
    • good
    • 0
この回答へのお礼

解答ありがとうございます。
明らかにおかしいですね。
fn[11]にすれば問題ないですよね?

お礼日時:2011/10/05 23:07

/* ベクトルの領域確保 */


x = dvector(1,n); /* x[1...n] */

ここのコメントと、dvector の関数の実装は一致しています。
でも、

for( i = 0 ; i <= n ; i++)
{
 …
input_vector2( x, t, i,fin, fout ); /* ベクトルxの入出力 */
 …
}

と、iが0からnまで動くのに input_vector2関数内で、

void input_vector2( double *b, double t,int i ,FILE *fin, FILE *fout)
{
 …
 fscanf(fin, "%lf", &b[i]);
 …
}

と x[0...n] に対して代入が行われることになるのは、どうなのでしょうか?
    • good
    • 0
この回答へのお礼

その通りでした。
要素の始めが1からになるように設定しているのに、0から代入している点に間違いがあったようです。
ありがとうございました。

お礼日時:2011/10/06 00:10

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!