こんにちはゲストさん。会員登録(無料)して質問・回答してみよう!

解決済みの質問

C言語のデバック 領域の二重解放が原因か??

学生で流体力学の研究を行っています。
研究の一環でフリーの数値解析ソフトを使っているのですが、ポスト処理の機能が弱いので、自作してみようと思い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 *)型へのキャストが必要 */
}

投稿日時 - 2011-10-05 20:01:02

QNo.7053613

困ってます

質問者が選んだベストアンサー

/* ベクトルの領域確保 */
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] に対して代入が行われることになるのは、どうなのでしょうか?

投稿日時 - 2011-10-05 23:35:43

お礼

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

投稿日時 - 2011-10-06 00:10:18

ANo.5

このQ&Aは役に立ちましたか?

1人が「このQ&Aが役に立った」と投票しています

回答(5)

ANo.4

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

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

まずは、fn のバッファの長さを適切にしてみては?
(最後のnull文字分も忘れずに!)

投稿日時 - 2011-10-05 22:20:06

お礼

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

投稿日時 - 2011-10-05 23:07:44

ANo.3

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

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

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

Valgrindで調べてみてはいかがでしょうか。

投稿日時 - 2011-10-05 21:53:18

お礼

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

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

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

投稿日時 - 2011-10-05 23:03:38

ANo.2

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

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

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

投稿日時 - 2011-10-05 21:32:02

ANo.1

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

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

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

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

って二重解放になりそうですよ。

投稿日時 - 2011-10-05 20:35:56

お礼

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

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

投稿日時 - 2011-10-05 21:16:17

あなたにオススメの質問