質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

4回答

301閲覧

多次元正方行列の積を求めたい

h_proc

総合スコア68

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/01/05 08:16

編集2019/01/05 09:22

正方行列の積を求めるコードを書いています。dt1,dt2,dt3という三つの正方行列を用意して、dt3にdt1×dt2の結果が入力されるようにしました。この時dt3には、{{11,14},{18,23}}が入るはずですが、{{15,20}{24,31}}となってしまいます。どこが間違っているのでしょうか。教えていただきたいです。
また、ついでの質問になってしまうのですが、n次正方行列のnは#define ARRAY_SIZE 2の定義方法(2の部分をその都度変えていく)であっているのでしょうか。また、その時の初期化はどのように行えばよいのでしょうか。
よろしくお願いいたします。

c

1#include <stdio.h> 2 3#define ARRAY_SIZE 2 4 5int doub(int dt1[ARRAY_SIZE][ARRAY_SIZE], int dt2[ARRAY_SIZE][ARRAY_SIZE], int dt3[ARRAY_SIZE][ARRAY_SIZE]); 6 7int doub(int dt1[ARRAY_SIZE][ARRAY_SIZE], int dt2[ARRAY_SIZE][ARRAY_SIZE], int dt3[ARRAY_SIZE][ARRAY_SIZE]) { 8 9 for (int i = 0; i < ARRAY_SIZE; i++) { 10 for (int j = 0; j < ARRAY_SIZE; j++) { 11 for (int k = 0; k < ARRAY_SIZE; k++) { 12 13 dt3[i][j] += dt1[i][k] * dt2[k][j]; 14 15 } 16 } 17 } 18 return dt3[ARRAY_SIZE][ARRAY_SIZE]; 19} 20 21int main(void) 22{ 23 int dt1[][ARRAY_SIZE] = { {1,2},{2,3} }; 24 int dt2[][ARRAY_SIZE] = { {3,4},{4,5} }; 25 int dt3[][ARRAY_SIZE] = { {0,0},{0,0} }; 26 27 doub(dt1, dt2, dt3); 28 29 printf("dt1×dt2=\n"); 30 31 for (int i = 0; i < ARRAY_SIZE; i++) { 32 for (int j = 0; j < ARRAY_SIZE; j++) { 33 printf("%3d", dt3[i][j]); 34 } 35 printf("\n"); 36 } 37 38 return 0; 39}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

h_proc

2019/01/05 09:32

すみません。私のミスでした。正しく実行されました。ありがとうございます。
episteme

2019/01/05 12:16

doub の戻り値は何を返したいのかしら? 返すもんがないなら void でええよ。
h_proc

2019/01/05 22:34

そうでした。返り値は毎回つけないといけないと思い込んでいました。ありがとうございます。
guest

回答4

0

ベストアンサー

質問文のコードでも {{11,14},{18,23}} になるようですが、
すこし書き換えてみました。
mat.c

c

1#include <stdio.h> 2 3#define ARRAY_SIZE 2 4 5void doub(int dt1[ARRAY_SIZE][ARRAY_SIZE], int dt2[ARRAY_SIZE][ARRAY_SIZE], int dt3[ARRAY_SIZE][ARRAY_SIZE]) { 6 for (int i = 0; i < ARRAY_SIZE; i++) { 7 for (int j = 0; j < ARRAY_SIZE; j++) { 8 dt3[i][j] = 0; 9 for (int k = 0; k < ARRAY_SIZE; k++) { 10 dt3[i][j] += dt1[i][k] * dt2[k][j]; 11 } 12 } 13 } 14} 15 16int main(void) 17{ 18 int dt1[][ARRAY_SIZE] = { {1,2},{2,3} }; 19 int dt2[][ARRAY_SIZE] = { {3,4},{4,5} }; 20 int dt3[][ARRAY_SIZE] = { {0,0},{0,0} }; 21 22 doub(dt1, dt2, dt3); 23 24 printf("dt1×dt2=\n"); 25 26 for (int i = 0; i < ARRAY_SIZE; i++) { 27 for (int j = 0; j < ARRAY_SIZE; j++) { 28 printf("%3d", dt3[i][j]); 29 } 30 printf("\n"); 31 } 32 return 0; 33}

実行例
イメージ説明

ARRAY_SIZE は行列の列数になってます。
doub で dt1[ARRAY_SIZE][ARRAY_SIZE] のようにしているので。

追記
2x2, 3x3 の行列も扱えるようにしてみたものを示します。

c

1#include <stdio.h> 2 3void doub(int n, int dt1[][n], int dt2[][n], int dt3[][n]) { 4 for (int i = 0; i < n; i++) { 5 for (int j = 0; j < n; j++) { 6 dt3[i][j] = 0; 7 for (int k = 0; k < n; k++) { 8 dt3[i][j] += dt1[i][k] * dt2[k][j]; 9 } 10 } 11 } 12} 13 14void show_matrix(int n, int dt[][n]) { 15 for (int i = 0; i < n; i++) { 16 for (int j = 0; j < n; j++) { 17 printf("%3d", dt[i][j]); 18 } 19 printf("\n"); 20 } 21} 22 23int main(void) 24{ 25 int dt2_1[2][2] = { {1,2},{2,3} }; 26 int dt2_2[2][2] = { {3,4},{4,5} }; 27 int dt2_3[2][2] = { {0,0},{0,0} }; 28 29 doub(2, dt2_1, dt2_2, dt2_3); 30 show_matrix(2, dt2_3); 31 printf("\n"); 32 33 int dt3_1[3][3] = { {1,2,3},{2,3,0},{0,0,1} }; 34 int dt3_2[3][3] = { {3,4,0},{4,5,0},{0,0,1} }; 35 int dt3_3[3][3]; 36 37 doub(3, dt3_1, dt3_2, dt3_3); 38 show_matrix(3, dt3_3); 39 40 return 0; 41}

実行例
イメージ説明

投稿2019/01/05 08:33

編集2019/01/05 09:58
katoy

総合スコア22324

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

h_proc

2019/01/05 09:31

ありがとうございます。解決しました。 n次の定義方法はこれであっているのでしょうか。あと、n次の場合、初期化は毎回行わないといけないのでしょうか。 度々申し訳ありません。よろしくお願いいたします。
katoy

2019/01/05 10:02

2x2 だけだなく、3x3 の積も計算する例を回答に追記しました。 値は毎回宣言 or 代入するひつyいうはあります。積の結果を収める行列は値は未設定でもよいです。(積を計算する処理中で値をすべて上書きするから)
h_proc

2019/01/05 22:41

ありがとうございます。最初のコードのままで、ARRAY_SIZE 3にする方法でも3次の計算は可能でしょうか。
katoy

2019/01/05 22:48

> ... 最初のコードのままで、ARRAY_SIZE 3 ... ご自分で試してみてください。 その上で問題・疑問がでたら、その詳細をお知らせください。
h_proc

2019/01/05 22:59

そうですね。やってみます。聞いてばかりですみません。
guest

0

こちらでコピペしてそのまま実行させたら、

dt1×dt2=
11 14
18 23

とでましたね
# VisualStudio2017community


んでついでに、

return dt3[ARRAY_SIZE][ARRAY_SIZE];

動作には関係ないですが、なにげに範囲外アクセスになってますね

投稿2019/01/05 08:27

編集2019/01/05 08:33
y_waiwai

総合スコア87774

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

h_proc

2019/01/05 09:24

範囲外アクセスとはどういうことでしょうか。このreturnは不要ですか。何もわかっていなくて、申し訳ありません。
y_waiwai

2019/01/05 11:11

dt3 の定義は、 int dt3[ARRAY_SIZE][ARRAY_SIZE] となってますが、これは、 dt3[0~ARRAY_SIZE-1][0~ARRAY_SIZE-1] までの範囲でしか領域の想定はされてません ってことで、 dt3[2][2] の読み出しは範囲外となります #まあ、読み出しだけなら不具合はなさそうですが
h_proc

2019/01/05 22:36

そうなんですね。全然知りませんでした。ありがとうございます。 ARRAY_SIZE 3にすれば有効になるということでしょうか。
namnium1125

2019/01/05 23:17 編集

いや多分元コードのままでは範囲外アクセスのままですよ…(dt3[3][3]にアクセスしてますので) まぁ元から要らない返り値に関する話題ですが() 返り値が不要であること(と範囲外アクセスであったこと)以外に元コードに問題はなかったように感じます。
guest

0

本質ではないですけど、dt3をゼロ行列で初期化しておかないと積関数の結果が合いませんよ。

まあ、初期化を関数の前でやれば良いのですが。

投稿2019/01/05 13:53

HogeAnimalLover

総合スコア4830

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

動的に次元を変更して計算させたいなら、malloc関数を使用して配列を動的に確保するか、予め大きめに配列を確保しておくという方法があります。

後者のほうが比較的楽です。

以下コード例

c

1#include <stdio.h> 2#include <stdlib.h> 3#define ARRAY_MAX_SIZE 256 4#define MEM 256 // 入出力用の定数ですので気にしないでください。 5 6// 入力用関数 7 8char* input(char* str, char* desc) { 9 printf(desc); 10 fgets(str, MEM, stdin); 11 return str; 12} 13 14void doub(int dt1[ARRAY_MAX_SIZE][ARRAY_MAX_SIZE], 15 int dt2[ARRAY_MAX_SIZE][ARRAY_MAX_SIZE], 16 int dt3[ARRAY_MAX_SIZE][ARRAY_MAX_SIZE], 17 int dim) { // dim は dimention の略 18 for (int i = 0; i < dim; i++) { 19 for (int j = 0; j < dim; j++) { 20 dt3[i][j] = 0; // 追加 21 for (int k = 0; k < dim; k++) { 22 dt3[i][j] += dt1[i][k] * dt2[k][j]; 23 } 24 } 25 } 26} 27 28int main(void) { 29 int 30 dt1[ARRAY_MAX_SIZE][ARRAY_MAX_SIZE], 31 dt2[ARRAY_MAX_SIZE][ARRAY_MAX_SIZE], 32 dt3[ARRAY_MAX_SIZE][ARRAY_MAX_SIZE]; 33 34 char str[MEM]; 35 int dim = atoi(input(str, "dim? : ")); 36 37 38 // 入力 39 40 printf("dt1\n"); 41 for (int i = 0; i < dim; i++) { 42 for (int j = 0; j < dim; j++) { 43 printf("i:%d j:%d : ", i, j); 44 dt1[i][j] = atoi(input(str, "")); 45 } 46 } 47 48 printf("dt2\n"); 49 for (int i = 0; i < dim; i++) { 50 for (int j = 0; j < dim; j++) { 51 printf("i:%d j:%d : ", i, j); 52 dt2[i][j] = atoi(input(str, "")); 53 } 54 } 55 56 // 計算 57 58 // doub(dt1, dt2, dt3); 59 doub(dt1, dt2, dt3, dim); 60 61 // 出力 62 63 printf("dt1 * dt2=\n"); 64 65 for (int i = 0; i < dim; i++) { 66 for (int j = 0; j < dim; j++) { 67 printf("%d ", dt3[i][j]); 68 } 69 printf("\n"); 70 } 71 72 return 0; 73}

入出力例:

$ ./tera dim? : 2 dt1 i:0 j:0 : 1 i:0 j:1 : 2 i:1 j:0 : 2 i:1 j:1 : 3 dt2 i:0 j:0 : 3 i:0 j:1 : 4 i:1 j:0 : 4 i:1 j:1 : 5 dt1 * dt2= 11 14 18 23

投稿2019/01/05 10:07

編集2019/01/05 14:41
namnium1125

総合スコア2043

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

namnium1125

2019/01/05 10:28 編集

コンパイルしなおすのが億劫なのだと仮定して回答しましたが、そうでないならば質問者様の方法も普通にアリだと思いますよ。
namnium1125

2019/01/05 14:42

dt3[i][j] = 0;という処理を忘れておりましたので追記しておきました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問