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

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

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

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

Q&A

1回答

1431閲覧

このプログラムをmainから関数化し、ファイル分割したいです。

john010

総合スコア9

C

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

0グッド

0クリップ

投稿2021/05/11 10:08

私はあるプログラムを作ったのですが、すべてmain文内につくってしまい、これを関数そして、ファイル分割をしてよりわかりやすくしたいです。どのように変更すればいいでしょうか?関数化してみたら、ポインタや引数がうまいあいませんでした。

プログラムの内容は、ユーザ 1 と好みが似ているユーザの ID をその度合い(類似性スコア)が高い順番に出力するものです。1行目にユーザの数を表す整数 N と書籍の数を表す整数 M が空白区切りで与えられる。続く N 行に N × M 個
の要素 e からなる行列が空白区切りで与えられる。ei,j はユーザ i の書籍 j に対する評価を表す。ただし、ei,j が負の値の場合、評価しなかったことを表すものとします。

C

1#include <stdio.h> 2#include <math.h> 3int main() 4{ 5 int N, M; //Nは行M、は列 6 scanf("%d%d", &N, &M); 7 double e[N][M]; //入力データを格納した 8 9 for (int i = 0; i < N; i++) 10 { 11 for (int j = 0; j < M; j++) 12 { 13 scanf("%lf", &e[i][j]); 14 } 15 } 16 17 double score[2][N]; 18 double sum[N]; 19 20 for (int i = 1; i < N; i++) 21 { 22 for (int j = 0; j < M; j++) 23 { 24 if (e[0][j] == -1 || e[i][j] == -1) 25 continue; 26 sum[i] += pow(e[0][j] - e[i][j], 2); 27 } 28 } 29 30 for (int i = 0; i < N; i++) 31 { 32 score[1][i] = 1 / (sqrt(sum[i]) + 1); 33 score[0][i] = i + 1; 34 } 35 //バブルソート 36 double tmp; 37 for (int i = 1; i < N - 1; i++) 38 { 39 for (int j = N - 1; j >= i + 1; j--) 40 { 41 if (score[1][j - 1] < score[1][j]) 42 { 43 tmp = score[1][j - 1]; 44 score[1][j - 1] = score[1][j]; 45 score[1][j] = tmp; 46 47 tmp = score[0][j - 1]; 48 score[0][j - 1] = score[0][j]; 49 score[0][j] = tmp; 50 } 51 } 52 } 53 54 for (int i = 1; i < N; i++) 55 { 56 printf("%d %lf\n", (int)score[0][i], score[1][i]); 57 } 58 59 return 0; 60}

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

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

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

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

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

mather

2021/05/11 10:28

どのように関数化するべきか、ファイル分割するべきか、という問いには正解はありません。 まずは自分でやってみてください。 > 関数化してみたら、ポインタや引数がうまいあいませんでした。 具体的にどんなコードを書いてどんなエラーが出たのか記載してください。
dodox86

2021/05/11 10:29

「わかりやすく」と言うのはどちらかと言うと主観的なことなので、第三者には分かりません。回答者による分割、関数化が質問者にとっては分かりづらくなる可能性もあります。「どのように変更すればよいでしょうか?」となると丸投げ感が伴うので、まずは質問者さんが関数化して問題になった部分「ポインタや引数がうまく渡せない?」を質問としてみてはどうでしょう。 たぶん、適切に関数に分けることが先決なのであって、ファイルを分割しなければならないことは無いです。
dodox86

2021/05/11 10:38 編集

まぁ、「こんな分け方、関数化はどうでしょう。」的な提案ベースの回答をいただけることはあるかもしれません。(ただし、それに期待をしてはいけません。私も回答は避けます)
hoshi-takanori

2021/05/11 14:03

質問の趣旨は、 ・プログラムのどの部分をどうやって切り出して関数化するかという一般論 ・C 言語の関数間で配列 (特に可変長 2 次元配列) をやり取りする具体的な方法 のどちらでしょうか? (後者に関しては C 言語ではいろいろ面倒すぎますよね…。) あと、どういうプログラムかにもよります。再利用を考慮した一般的なプログラミング手法を前提とするか、特定の環境に最初から最適化して書いてしまうかですね。(特に、競プロであれば N, M の最大値が提示されてると思うので、最大サイズのグローバル配列を作ってしまうとか…。)
guest

回答1

0

このコードには大きな塊が5個あります。それぞれは1重か2重のforループです。
このそれぞれの塊が何をしているのか、何を受け取って何を出しているのかをコメント行に書いてみましょう。

最初のforループに私がコメントを付けるとすると、

N人のユーザのM冊の本の読書評価を準備する。
受け取るもの:なし
出すもの:読書評価の入った2次元配列

です。

大事なことはファイルから読み込むという手段(HOW)ではなく、目的(WHAT)を書くことです。また、受け取るものとはそのループの前から受け取るものという意味で、scanfはその中の処理なので「なし」としています。

このように全ての塊についてコメントを付け、それを眺めてみて、john010さんがどう分けたいかを考えてみましょう。私のコメントとjohn010さんのコメントは同じではないでしょうし,分け方も同じではないでしょう。それでいいのです。

そうやって分けたものを一つづつの関数にしましょう。関数の名前はコメントに書いた「目的」を表すものにしましょう。関数の引数は、「受け取るもの」です。関数の値は「出すもの」です。

注意事項:
C言語は、本当の意味での2次元配列を引数で渡すことが出来ません。
そのため、今は2次元配列で書いてあるものをポインタへのポインタに書き換えなければならないことが多いのです。これは、C言語で再利用できる関数を書くための必須スキルですので、頑張って覚えるしかありません。
分からないときは、teratailで質問すれば誰かが教えてくれるでしょう。

投稿2021/05/11 14:20

ppaul

総合スコア24670

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問