学生で流体力学の研究を行っています。
研究の一環でフリーの数値解析ソフトを使っているのですが、ポスト処理の機能が弱いので、自作してみようと思い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 *)型へのキャストが必要 */
}
No.5ベストアンサー
- 回答日時:
/* ベクトルの領域確保 */
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] に対して代入が行われることになるのは、どうなのでしょうか?
その通りでした。
要素の始めが1からになるように設定しているのに、0から代入している点に間違いがあったようです。
ありがとうございました。
No.3
- 回答日時:
>>なぜそこが二重解放になるのでしょうか?
>
>そのようなケースがありえるのかわかりませんが
>nl1 が 0 のときには起こりえそうですよ。
すいません。勘違いでした。
なりませんね。
Valgrindで調べてみてはいかがでしょうか。
何度もありがとうございます。
私自身もfree_dmatrixなどはあまり分からずに使っているのですが、同じものを何度か使っていままでエラーがなかったのでたぶん問題はないだろうと思います。
既存の問題のないプログラムから変更した箇所はメイン関数の部分とinput_vectorだけなのでそのあたりのどこかがおかしいのだと思うんですが、わからないです。
Vargrindというデバックツール(?)があるんですね。
導入が私には難しそうなので、どうしようもなかったら使ってみようと思います。
ありがとうございました。
No.2
- 回答日時:
>なぜそこが二重解放になるのでしょうか?
そのようなケースがありえるのかわかりませんが
nl1 が 0 のときには起こりえそうですよ。
余計なお世話なんでしょうが
dmatrix, free_dmatrix
は、無駄に難しい気がするので
リファクタリングした方がいいと思います。
No.1
- 回答日時:
>実行ディレクトリ内には各時刻(以下のプログラム内では t)のディレクトリが存在し、その中に圧力(p)のデータが存在しています。
不具合が発生する状況が確認できないので、よくわかりません。
質問する場合は、問題が再現する状態をすべて提示してください。
とりあえずコードを見ましたが
free_dmatrixの
/* メモリの解放 */
for ( i = nr1 ; i <= nr2 ; i++) free((void *)(a[i]+nl1));
free((void *)(a+nr1)); ←ここ
って二重解放になりそうですよ。
素早い解答どうもありがとうございます。
「問題が再現する状態」とは何なのかよくわからないですが、
「実行ディレクトリ内には各時刻(以下のプログラム内では t)のディレクトリが存在し、その中に圧力(p)のデータが存在しています。」の一文がよくわからなかったということですか?これなら大丈夫ですか?舌足らずですいません。
「プログラムを実行するディレクトリ内には各時刻(0.0001~0.0004 プログラム中では変数tで表しています)のディレクトリが存在し、その中に圧力(p)のデータが存在しています。」
なぜそこが二重解放になるのでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# バイナリファイルをコピーするのにかかる時間を測りたいのですが実行するとFatel error:gli 2 2022/11/03 01:10
- C言語・C++・C# プログラミングの授業の課題です 1 2023/01/17 22:15
- C言語・C++・C# c言語でユーザ関数を利用して複素数のべき乗と絶対値の数列を計算するプログラムが作りたいです。 3 2023/01/29 22:13
- C言語・C++・C# C 言語の Gauss Jordan 法について 2 2022/12/28 11:16
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# C言語のエラーについて 2 2022/07/11 13:56
- C言語・C++・C# Cのdoubleの浮動小数点表示について 3 2023/04/17 13:14
- C言語・C++・C# 並列プログラミングのπ計算について 1 2022/07/16 22:30
- C言語・C++・C# プログラミングを教えて欲しいです。 配列aは、int a[9]={7,6,12,8,3,5,10,9 4 2022/12/19 23:27
- C言語・C++・C# 10個の実数に対する降順ソート結果を出力するプログラムを作りたいのですが、以下のプログラムをどう直せ 1 2022/07/09 22:16
このQ&Aを見た人はこんなQ&Aも見ています
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
プログラムでの数字につく”f”の...
-
doubleの変数にintとintの割り...
-
C言語の型による処理速度の違い
-
ガウスの掃き出し法によるC++プ...
-
浮動小数点の定数
-
-1.#IND00と出てしまうのですが...
-
カウントアップタイマ
-
C言語のpow関数の不具合
-
C 開放してるのにエラー(doubl...
-
float型とdouble型の変数の違い...
-
C言語でintをdoubleに
-
P値(統計学)を求めるプログラム
-
doubleは常に%lfとするべきなのか
-
C言語のデバック 領域の二重解...
-
Cで3乗根を求める方法
-
C++で外積
-
たくさんの数の平均を求める方...
-
関数におけるif文とreturn文に...
-
C言語でのFFT(構造体とポインタ...
-
3次方程式の求解プログラム(...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
プログラムでの数字につく”f”の...
-
doubleの変数にintとintの割り...
-
float型とdouble型の変数の違い...
-
c言語で、繰り返し文の中で、0....
-
C言語を実行すると-infが出てき...
-
C言語 関数プロトタイプ宣言の...
-
C 開放してるのにエラー(doubl...
-
C言語の型による処理速度の違い
-
至急です! マクロ定義で #defi...
-
関数におけるif文とreturn文に...
-
c言語のプログラミングについて...
-
2分法で方程式の複数の解を自...
-
-1.#IND00と出てしまうのですが...
-
doubleは常に%lfとするべきなのか
-
C言語のpow関数の不具合
-
C言語で-23乗を取り扱うには
-
C言語で台形公式を使った二重積...
-
Cで3乗根を求める方法
-
sin(x)の近似について
-
2次方程式の解を求めるプログ...
おすすめ情報