- ベストアンサー
C言語での行列計算に関する問題
- セグメントエラーが発生している C 言語の行列計算関数とプログラムについて相談しました。
- 関数 matprod の引数やループ処理に問題がある可能性があります。
- 間違いを見つけることができる方にお教えいただきたいです。
- みんなの回答 (4)
- 専門家の回答
質問者が選んだベストアンサー
★追記。 ・ちょっと同じような処理を書いてみました。 解説はしませんのでソースを読み取ってみて下さい。 でも注目して欲しい点は (1)new_matrix 関数の行列確保 (2)free_matrix 関数の行列解放 (3)disp_matrix 関数の行列表示 の3つです。 ・2次配列を動的に確保していますが malloc(calloc)、free の回数が少ないです。 この方法ならメモリ不足で free したり、行列解放の free の回数がわずか 2 回です。 過去質問を参考にどうぞ。 http://oshiete1.goo.ne.jp/qa3022605.html→『callocで二次元配列を作成するには?』 ・では下のソースをご覧下さい。 ソース: #include <stdio.h> #include <stdlib.h> // 行列の確保 double **new_matrix( int nrow, int ncol ) { double **aa; double *a; int i; if ( (aa = (double **)calloc(nrow + 1,sizeof(double*))) != NULL ){ if ( (a = (double *)calloc(nrow * ncol,sizeof(double))) != NULL ){ for ( i = 0 ; i < nrow ; i++ ){ aa[ i ] = &a[ i * ncol ]; } aa[ nrow ] = NULL; // 行数の末尾判定の工夫 return aa; // 正常 } free( aa ); } return NULL; // 確保エラー } // 行列の解放 void free_matrix( double **a ) { if ( a != NULL ){ free( a[0] ); free( a ); } } // 行列の表示 void disp_matrix( double **a, int nrow, int ncol ) { int x, y; for ( y = 0 ; y < nrow ; y++ ){ for ( x = 0 ; x < ncol ; x++ ){ printf( "%.f ", a[y][x] ); } printf( "\n" ); } printf( "\n" ); } // 行列の初期化(ダミーセット) void dummy_matrix( double **a, int nrow, int ncol ) { int x, y; for ( y = 0 ; y < nrow ; y++ ){ for ( x = 0 ; x < ncol ; x++ ){ a[ y ][ x ] = ncol * y + x; } } } // 行列処理 void matprod( int nrow, int ncol, double **a, double **b, double **prod ) { int i, x, y; for ( y = 0 ; y < nrow ; y++ ){ for ( x = 0 ; x < ncol ; x++ ){ for ( i = 0 ; i < ncol ; i++ ){ prod[ y ][ x ] = a[i][x] * b[y][i]; } } } } // メイン関数 int main( void ) { int success = 0; // 成功フラグ int nrow = 3; // 行数 int ncol = 3; // 列数 double **a, **b, **prod; // 3×3行列を3つ確保 if ( (a = new_matrix(nrow,ncol)) != NULL ){ if ( (b = new_matrix(nrow,ncol)) != NULL ){ if ( (prod = new_matrix(nrow,ncol)) != NULL ){ // aの初期化,表示 dummy_matrix( a, nrow, ncol ); disp_matrix( a, nrow, ncol ); // bの初期化,表示 dummy_matrix( b, nrow, ncol ); disp_matrix( b, nrow, ncol ); // 行列の計算,表示 matprod( nrow, ncol, a, b, prod ); disp_matrix( prod, nrow, ncol ); success = 1; free_matrix( prod ); } free_matrix( b ); } free_matrix( a ); } if ( success == 0 ){ printf( "3×3行列をメモリ確保できませんでした。\n" ); return 1; } return 0; } 以上。
その他の回答 (3)
- Oh-Orange
- ベストアンサー率63% (854/1345)
★追記。 >肝心の計算結果が出てきません。。><・・。 ↑ これって計算結果が正しくないという意味ですか? ・matprod 関数は行列の掛け算ですよね? だとすると行列の計算ロジックが間違っていますね。 間違い⇒prod[ y ][ x ] = a[i][x] * b[y][i]; 正しい⇒prod[ y ][ x ] += a[i][x] * b[y][i]; となりませんか。 ・以上。回答 No.3 の matprod 部分も修正して下さい。
- Oh-Orange
- ベストアンサー率63% (854/1345)
★アドバイス >肝心の計算結果が出てきません。。><・・。 ↑ これは正しい計算結果が出ないのでしょうか? それとも全く計算結果が表示されないのでしょうか? どういう意味? >助けてください!!!! ↑ どこの何を。 せめてどの関数のどの場所か補足してくれないとね。 行列プログラムのようですね。 行列の計算方法を忘れてしまいました。 ・とりあえず prod がメモリ確保されていないのでバグとなっています。 行列の為に2次配列を動的確保しているのならば matprod 関数の引数は最初の方法に 戻して下さい。それであっているので。 ちなみに『セグメントエラーで実行できません。』というのは prod が確保されていない エラーです。これが原因でした。 まずはソースを最初の『double **a』に引数を戻してから prod を new_matrix 関数で 確保して下さい。 ・以上。
- Oh-Orange
- ベストアンサー率63% (854/1345)
★関数の引数定義を修正しましょう。 ・間違い⇒double **a 正しい1⇒double (*a)[3] 正しい2⇒double a[3][3] ※同様に『b』『prod』も修正します。 もう一つの方法: ・配列の要素が可変の場合は引数を『**a』として for ( k = 0 ; k < ncol ; k++ ){ double aa = a[ k * ncol + j ]; double bb = b[ i * ncol + k ]; prod[ i * ncol + j ] = aa * bb; } と配列位置を計算してアクセスします。 ・以上。
補足
#include <stdio.h> #include <stdlib.h> double * vector; double ** matrix; double * new_vector(int n); /* n×1 ベクトルの作成 */ double ** new_matrix(int nrow, int ncol); /* nrow行ncol列の行列の作成 */ void free_vector(double * v); /* ベクトルの消去 */ void free_matrix(double ** a); /* 行列の消去 */ void vecprint(double * v, int n); /* n×1 ベクトルの表示 */ void matprint(double ** a, int ncol); /* 行列の表示 */ /* ベクトルv1とベクトルv2の和をベクトルsumに代入する */ void vecsum(int n, double * v1, double * v2, double * sum); void matprod(int nrow,int ncol,double a[3][3],double b[3][3],double prod[3][3]); int main() { int i, j, nrow, ncol; double *v1, *v2, *v3; double **a,**b,**prod; nrow = 3; /* 行の数 */ ncol = 3; /* 列の数 */ a = new_matrix(nrow, ncol); /* 行列を作る */ for (i = 0; i < nrow; i++) for (j = 0; j < ncol; j++) a[i][j] = 1.0 * i + j; /* 行列の要素の代入 */ printf("%d × %d 行列:\n", nrow, ncol); matprint(a, ncol); /* 出力 */ b = new_matrix(nrow, ncol); /* 行列を作る */ for (i = 0; i < nrow; i++) for (j = 0; j < ncol; j++) b[i][j] = 1.0 * i + j; /* 行列の要素の代入 */ printf("%d × %d 行列:\n", nrow, ncol); matprint(b, ncol); /* 出力 */ matprod(3,3,a,b,prod); for(i=0;i<nrow;i++){ for(j=0;j<ncol;j++){ printf("%lf",prod[i][j]); //3*3の計算をして、答えを表示する。 }} return; } double * new_vector(int n) { double * v; v = malloc(sizeof(double) * n); if (v == NULL){ fprintf(stderr, "\n記憶領域不足.\n"); exit; } return v; } double ** new_matrix(int nrow, int ncol) { int i; double ** a; a = malloc((nrow + 1) * sizeof(void *)); if (a == NULL){ fprintf(stderr, "\n記憶領域不足.\n"); exit; } for (i = 0; i < nrow; i++) { a[i] = malloc(sizeof(double) * ncol); if (a[i] == NULL) { while (--i >= 0) free(a[i]); free(a); fprintf(stderr, "\n記憶領域不足.\n"); exit(EXIT_FAILURE); } } a[nrow] = NULL; /* 行の数を自動判断するための工夫 */ return a; } void free_vector(double * v) { free(v); } void free_matrix(double ** a) { double ** b; b = a; while (*b != NULL) free(*b++); free(a); } void vecprint(double * v, int n) { int j; for (j = 0; j < n; j++) { printf("%0.f ", v[j]); } printf("\n"); } void matprint(double ** a, int ncol) { int i; for (i = 0; a[i] != NULL; i++) { vecprint(a[i], ncol); } } void vecsum(int n, double * v1, double * v2, double * sum) { int i; for(i=0; i<n; i++) sum[i] = v1[i] + v2[i]; return; } void matprod(int nrow,int ncol,double a[3][3],double b[3][3],double prod[3][3]){ int i,j,k; for(i=0;i<nrow;i++){ for(j=0;j<ncol;j++){ for(k=0;k<ncol;k++){ prod[i][j]=a[k][j]*b[i][k];} } } } このプログラムを動かそうとしています。 セグメントエラーはなくなったのですが・・・。 肝心の計算結果が出てきません。。><・・。 助けてください!!!!
お礼
Oh-Orangeさん。 何度も私の初歩的な質問にご回答ありがとうございました。 無事にプログラムを作成することができました!! プログラミングが楽しく思えました★ Oh-Orangeさんみたいな人がこの教えてgooにいることを嬉しく思います>< 本当にありがとうございます!!!