プロが教えるわが家の防犯対策術!

教えていただきたいのですが、C言語で名前と点数を入力して合計と平均を求めるというプログラムを作ったのですが、
main関数の中で情報入力、合計と平均の計算をしているのでそれぞれ入力関数、合計を求める関数、平均を求める関数というものを作ってmain関数をすっきりとさせたいのですがどうすればいいですか?

#include <stdio.h>

typedef struct{
char name[15];
int jpn;
int eng;
int math;
int sum;
} stdent;

typedef struct{
double sum;
double jpn;
double eng;
double math;
} Score;

void maxmin(stdent *, int);

main()
{

int i, n;
n = 5;
stdent person[n];
Score average;

average.jpn = 0;
average.eng = 0;
average.math = 0;
average.sum = 0;

for(i = 0; i < n; i++)
{
printf("Student No.%d \n",i + 1);
printf("Name? ");
scanf("%s", person[i].name);
printf("Japanese? ");
scanf("%d", &(person[i].jpn));
printf("English? ");
scanf("%d", &(person[i].eng));
printf("Math? ");
scanf("%d", &(person[i].math));
printf("\n");

person[i].sum = person[i].jpn + person[i].eng + person[i].math;

average.jpn += person[i].jpn;
average.eng += person[i].eng;
average.math += person[i].math;
average.sum += person[i].sum;
}

average.jpn /= n;
average.eng /= n;
average.math /= n;
average.sum /= n;


printf(" 名前 国語 英語 数学 \n");
printf("------------------------------------\n");

for(i = 0; i < n; i++)
{
printf("%8s %3d %3d %3d %3d\n", person[i].name, person[i].jpn, person[i].eng, person[i].math, person[i].sum);
}

printf("------------------------------------\n");
printf("平均 %.1lf %.1lf %.1lf %.1lf\n\n", average.jpn,average.eng,average.math,average.sum);

return 0;
}

A 回答 (3件)

こんな感じでどうでしょうか?



=== ここからソース ==============================================
// Seiseki.cpp : コンソール アプリケーションのエントリ ポイントを定義します。
//

#include "stdafx.h"

// 配列の要素数を計算するマクロです
// 毎回sizeof()で書くより
// プログラムがわかりやすくなります
#define ARRAY_OF(a) (sizeof (a) / sizeof (a[0]))


// 人数を定義します
#define STUDENT_COUNT5

// 成績を格納する領域です
// 構造体配列でも作れますが、教科を通じての合計を取るのであれば
// 2次元配列のほうが適しています

// 各教科のインデックス
#define JAPANEASE0// 国語
#define ENGLISH1// 英語
#define MATHEMATICS2// 数学

// 各教科名を格納しておきます
// 各教科のインデックス順に並んでいなければなりません
static char* SubjectName[] = {"国語", "英語", "数学"};

// 個人の成績用構造体です
// 各教科毎に別のフィールドにせず
// 配列にしたほうが
// 合計や平均をとる関数がすっきりします
#define MAX_NAME_LENGTH 15// 氏名の最大長です
struct student
{
char Name[MAX_NAME_LENGTH + 1];// 氏名
int Score[ARRAY_OF (SubjectName)];// 各教科の得点
};


// データ格納域
// 2次元配列です
// 1次元目で生徒を識別します
// 2次元目で科目を識別します
static struct student person[STUDENT_COUNT];

// 合計を求める汎用関数です
// int型専用です
static int GetTotalInt(int Data[], int Count)
{
int s = 0;
int i;
for (i = 0; i < Count; ++i)
{
s += Data[i];
}
return s;
}

// 合計を求める汎用関数です
// doble型専用です
static double GetSumDoble(double data[], int Count)
{
int i;
double s = 0;
for (i = 0; i < Count; ++i)
{
s += data[i];
}
return s;
}


// 指定教科の合計点を求めます
static int GetSubjectsTotal(int SubjectNo)
{
int s = 0;// 合計用
int i;// 生徒用

for (i = 0; i < ARRAY_OF(person); ++i)
{
s += person[i].Score[SubjectNo];
}

return s;
}

// 指定教科の平均点を求めます
static double GetSubjectsAverage(int SubJectNo)
{
return GetSubjectsTotal(SubJectNo) * 1.0 / (ARRAY_OF(person));
}

// 成績を入力させる関数です
void InputData()
{
int i;

// 生徒数分データを入力させます
// ARRAY_OFにより人数を計算しているので
// 生徒数が変わっても、
// ここは全く変更の必要がないことに注目してください
for (i = 0; i < ARRAY_OF (person); ++i)
{
int j;

printf("Student No.%d \n", i + 1);
printf("Name? ");
scanf("%s", person[i].Name);


// 各教科の得点を入力させます
// 各教科の得点を配列にしたことで
// ARRAY_OFによる教科数の計算が可能になりました
// 教科の名称をテーブル化したことで
// 教科に増減・変更があっても
// ここの部分は全く変更を受けません
for (j = 0; j < ARRAY_OF (person[0].Score); j++)
{
printf("%s? ", SubjectName[j]);
scanf("%d", &(person[i].Score[j]));
}

}
}

// 成績を表示します
static void DisplayScore()
{
int i;
double Ave[ARRAY_OF (SubjectName)];// 教科毎の平均値格納用

printf("名前 ");

// 教科名を列挙します
for (i = 0; i < ARRAY_OF (SubjectName); i++)
{
printf("%s ", SubjectName[i]);
}
printf("\n");


// 生徒の成績を合計とともに表示します
for (i = 0; i < ARRAY_OF (person); i++)
{
int j;

// 氏名を表示します
printf("%15s ", person[i].Name);

// 教科別の得点を表示します
for (j = 0; j < ARRAY_OF (person[0].Score); j++)
{
printf("%3d ", person[i].Score[j]);
}

// 合計を表示し改行します
printf("%3d\n", GetTotalInt(person[i].Score,
ARRAY_OF (person[0].Score)));

}

// 各教科の平均点を表示します
// 平均の合計を取りやすくするため、一旦配列に格納します
printf("平均 ");
for (i = 0; i < ARRAY_OF (person[0].Score); i++)
{
Ave[i] = GetSubjectsAverage(i);
printf("%.1f ", Ave[i]);

}
// 平均の合計を表示します
printf("%.1f", GetSumDoble(Ave, ARRAY_OF(Ave)));

}


int main(int argc, _TCHAR* argv[])
{
// 成績を入力させます
InputData();


// 結果を表示します
DisplayScore();

return 0;
}

===================== ここまで ソース =====================

ポイントは
各関数の役割分担を明確にすること
各関数に必要以上の知識を持ちこませないこと
各関数には役割にふさわしい名前をつけること

です。


例えば、教科毎の合計を求める関数では
各人のデータが分かればよいのです。
具体的な教科名を知る必要性は全くないです。

そのためには、jpn, engといった教科と結びついた変数でなく
配列を使うのです。
配列を使うことで具体的な教科を隠し、
単なる得点データへと抽象化します。

抽象化することで教科と分離されたので
教科が変更になっても
(例えば 国語の代わりに理科を入れる)
変更は最小限で済みます

教科ごとの集計関数などは全く影響を受けず、
プログラム的にもスッキリします。
    • good
    • 0
この回答へのお礼

ありがとうございます。
これを参考にしてがんばってみます。

お礼日時:2009/05/18 13:12

main関数とは別の関数を作って、main関数からその関数を呼び出す、


という形のコードをこれまでに書かれたことはありますか?
    • good
    • 0

ハードコピーにマーカーで「ここはデータを入力してるところ」とか「ここで計算してる」とか書いて, それぞれを関数に切り出せばいいだけ

だと思う.
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!