2 Lesson 8-1 アンケート集計

2.1 問題

Lesson 8-1
以下のような予想結果を10人分入力し、男女別の予想結果を「勝ち・引き分け・負け」に 分けて集計し、表示するプログラムを構造体を利用して作成しなさい。
	あるスポーツの勝敗予想
	 1人目の予想 (男性:M) ホームチーム 勝ち:1
	 2人目の予想 (男性:F) ホームチーム 負け:2
	  ・
	  ・
	  ・
	10人目の予想 (男性:F) ホームチーム 引き分け:0

2.2 問題分析と構造体

2.2.1 問題分析

問題は単純である。10人分の予想結果を入力し、男女別に勝敗の予想人数を集計し、表示 するプログラムである。ここで構造体を使うとしたら、各人の情報(データ)に対してであ る。各人が持つ情報は、 の2種類である。ということで、図1のように10個のこれらを格納する構造 体を使うことにする。
図 1: 勝敗予想の基本情報
\includegraphics[keepaspectratio,scale=1.0]{figure/img_struct_1.eps}

集計結果も構造体にすることも可能であるが、教科書の解答の通り、配列を使うことにす る。集計結果は全て男女別の勝敗予想の人数で、同じ性質の整数の集まりなので、配列で も十分である。

2.2.2 構造体の定義

各人の情報は性別と勝敗予想である。それが10人分ある。10人同じ情報があるので、それ は配列にするのが良いだろう。各個人の情報は、構造体で一つの変数にまとめると分かりや すくて良い。性別と勝敗予想を一つの変数にまとめるために、C言語では次のように書く。
	struct datatype{
	  char sex;
	  int toto;
	};
datatypeという構造体を定義し、その中には性別を表す文字型(char)の変数 sexと、勝敗予想を表す整数型(int)の変数totoがある。これら2つの変数 を構造体datatypeのメンバーと言う。これで、図2のような 変数が定義できたのである。
図 2: 構造体のイメージ。構造体(struct datatype)は2つのメンバーがある。
\includegraphics[keepaspectratio,scale=1.0]{figure/diff_struct_1.eps}

文字型変数sexに1文字を格納して各人の性別を表す。例えば、メンバーのsex

とする。整数型変数totoには、ホームチームの試合の予想結果を表す。例えば、メ ンバーtotoは、ホームチームの勝敗として とする2。ここ で、メンバーsexfmが男性や女性、0,1,2が引き分けや勝ち負け を表すと決めたのはプログラマーであり、コンピューターはなにも関知していない事を忘 れてはならない。

これで、データ構造の内容が決まった。新しい変数の型として構造体を定義した。まだ、データの型の定義が終わっただけで、コンピューターのメモリーの確保が終わっ ていない。実際にデータを操作する場合、メモリーを確保する事が必要である。これは、 プログラム中で

	struct datatype data[10];
と書けばよい。そうすると、図3のようにメモリーが確保され る。
図 3: メモリー中の構造体のデータ
\includegraphics[keepaspectratio,scale=1.0]{figure/struct_memory_1.eps}

2.2.3 構造体のメンバーへのアクセス

これで、データの構造が決まったので、あとはそれぞれのメンバーにアクセスする方法が 分かれば、構造体の全てが分かる。構造体のメンバーへのアクセスの前に通常の変数と配 列のデータへのアクセスの方法を復習する。通常の変数、例えばaという変数へのア クセスは容易で、変数名を使えばそのデータを参照できる。次に配列であるが、それは配 列名と添え字を示すことによりデータにアクセスできる。例えば、b[3]とかである。

データは構造体のメンバーに格納されているから、それにアクセスするためには、構造体 名とメンバー名を示す必要がある。実際のアクセスの方法については、既に学習したように、ドット演算子をつかう。ここでは、次のように使われている。

	data[loop].sex
	data[loop].toto

2.3 プログラム例

この問題のプログラム例 (toto.c) をリスト1に示す。このプログラムは、グローバルな部分と4つの関数 からできておりそれぞれの動作は以下の通りである。

2.3.1 グローバル

10-13行
構造体の定義
17-19行
関数プロトタイプの宣言

2.3.2 main関数

25行
メイン関数の始まり。メイン関数の終わりは、39行である。
28行
構造体変数の宣言。 これは、配列型の構造体を宣言して、メモリーを確保している。
29行
集計結果を格納する配列の宣言。この配列には、以下のようなデータが格納される。
		result[0][0] : 女性で引き分けと予想した人数
		result[0][1] : 女性で勝ちと予想した人数
		result[0][2] : 女性で負けと予想した人数
		result[1][0] : 男性で引き分けと予想した人数
		result[1][1] : 男性で勝ちと予想した人数
		result[1][2] : 男性で負けと予想した人数
33行
データ入力用の関数の呼び出し。
34行
結果集計の関数の呼び出し。
35行
結果出力の関数の呼び出し。
38行
メイン関数が戻り値を返して、呼びだし元へ戻る。
39行
メイン関数のブロックの終わりを示している。

2.3.3 データ入力関数(data_input)

55行
データ入力関数の開始
56行
ループのカウンターに用いる変数宣言
57行
キーボード入力の時にバッファーに残るゴミを入れる。
62-68行
for文による10回のループ
63行
性別の入力を促す。
64行
scanf関数によりキーボードからデータを取得して、構造体変数 data[loop]のメンバーsexに格納する。
66行
ホームチームの勝敗の入力を促す。
67行
scanf関数によりキーボードからデータを取得して、構造体変数 data[loop]のメンバーtotoに格納する。
70行
関数が戻り値を返して、呼びだし元へ戻る。
71行
関数のブロックの終わりを示している。

2.3.4 データの集計関数(calc_result)

93行
データ入力関数の開始
94行
ループのカウンターに用いる変数宣言
97-101行
人数を格納する配列をゼロに初期化する。
103-109行
男女別勝敗の人数のカウント
111行
関数が戻り値を返して、呼びだし元へ戻る。
112行
関数のブロックの終わりを示している。

2.3.5 結果出力関数(print_result)

これは説明するまでもないであろう。各自考えよ。

2.3.6 プログラムリスト

リスト1:アンケートの集計

001: /*==================================================================*/
002: /*==================================================================*/
003: /*           教科書 「C言語プログラミング初歩の初歩」                    */
004: /*                練習問題 8 Lesson 8-1 アンケートの集計               */
005: /*==================================================================*/
006: /*==================================================================*/
007: #include <stdio.h>
008: 
009: /* ---- 構造体 ---- */
010: struct datatype{
011:   char sex;       /* 性別を表す文字         m:男性  f:女性     */
012:   int toto;       /* 予想結果を記憶する整数  0:引分  1:勝  2:負 */
013: };
014: 
015: /* ---- プロトタイプ宣言 ---- */
016: 
017: int data_input(struct datatype data[]);
018: int calc_result(struct datatype data[], int result[][3]);
019: int print_result(int result[2][]);
020: 
021: 
022: /*==================================================================*/
023: /*           メイン関数                                              */
024: /*==================================================================*/
025: int main(void){
026: 
027:   /* ---- 変数宣言 ---- */
028:   struct datatype data[10];  /* 構造体の宣言 */
029:   int result[2][3];          /* 勝敗予想人数[0:男 1:女][0:引分 1:勝 2:負]*/
030: 
031:   /* ---- 実行文 ---- */
032: 
033:   data_input(data);              /* データ入力関数呼び出し */
034:   calc_result(data, result);     /* 結果集計関数の呼び出し */
035:   print_result(result);          /* 結果表示関数の呼び出し */
036:   
037:   
038:   return 0;
039: }
040: 
041: 
042: /*==================================================================*/
043: /*  データの入力                                                     */
044: /*   [引数]                                                         */
045: /*      仮引数  data[] : 予想結果を格納する構造体 参照渡し               */
046: /*   [戻り値]                                                       */
047: /*            int : 常に 0 が返される                                */
048: /*   [動作内容]                                                      */
049: /*      ユーザーに入力を促し、キーボードから入力された 男性 or 女性 と    */
050: /*      勝敗予想を引数で渡された構造体に格納する。                        */
051: /*            男性 f   女性 m                                        */
052: /*            勝ち 1   引き分け 0   負け 2                            */
053: /*            これらの値は、予想結果を格納する構造体 data[] に格納される   */
054: /*==================================================================*/
055: int data_input(struct datatype data[]){
056:   int loop;             /* 読み込み番号のカウンター      */
057:   char temp;            /* バッファーに残ったゴミを入れる */
058: 
059: 
060:   /* ---- 勝敗予想の入力 ---- */
061: 
062:   for(loop = 0; loop < 10; loop++){
063:     printf("%d人目の予想をする方の性別は?  女性:f  男性:m\n",loop+1);
064:     scanf("%c%c", &data[loop].sex, &temp);
065: 
066:     printf("ホームチームの試合?  勝ち:1   引き分け:0   負け:2\n");
067:     scanf("%d%c", &data[loop].toto, &temp);
068:   }
069: 
070:   return 0;
071: }
072:     
073: 
074: /*==================================================================*/
075: /* データの集計                                                  */
076: /*   [引数]                                                         */
077: /*      仮引数  data[]    : 予想結果が格納されている構造体 参照渡し       */
078: /*             result[][]: 集計結果の集計を格納する配列   参照渡し       */
079: /*                            result[0:女性 1:男性][0:引分 1:勝 2:負] */
080: /*   [戻り値]                                                        */
081: /*            int : 常に 0 が返される                                 */
082: /*   [動作内容]                                                      */
083: /*      予想結果の集計をおこなう。各場合における人数は配列result[][]       */
084: /*      に格納される。                                                */
085: /*      勝敗予想を引数で渡された構造体に格納する。                        */
086: /*            result[0][0] : 女性で引き分けと予想した人数               */
087: /*            result[0][1] : 女性で勝ちと予想した人数                 */
088: /*            result[0][2] : 女性で負けと予想した人数                 */
089: /*            result[1][0] : 男性で引き分けと予想した人数               */
090: /*            result[1][1] : 男性で勝ちと予想した人数                 */
091: /*            result[1][2] : 男性で負けと予想した人数                 */
092: /*==================================================================*/
093: int calc_result(struct datatype data[], int result[][3]){
094:   int loop1, loop2;
095: 
096:   /* ---- 初期化 ---- */
097:   for(loop1=0; loop1<2; loop1++){
098:     for(loop2=0; loop2<3; loop2++){
099:       result[loop1][loop2]=0;         /* 勝敗予想人数の配列を全てゼロに */
100:     }
101:   }
102: 
103:   for(loop1=0; loop1<10; loop1++){
104:     if(data[loop1].sex == 'f'){
105:       result[0][data[loop1].toto]++;  /* 女性の場合 */
106:     }else{
107:       result[1][data[loop1].toto]++;  /* 弾性の場合 */
108:     }
109:   }
110: 
111:   return 0;
112: }
113: 
114: /*==================================================================*/
115: /*           結果表示                                                */
116: /*==================================================================*/
117: int print_result(int result[][3]){
118: 
119:   printf("\n##集計結果表示##\n");
120:   printf("女性の予想は、[勝ち:%2d][引き分け:%2d][負け:%2d]\n",
121:      result[0][1],result[0][0],result[0][2]);
122:   printf("男性の予想は、[勝ち:%2d][引き分け:%2d][負け:%2d]\n",
123:      result[1][1],result[1][0],result[1][2]);
124: 
125:   return 0;
126: }
\fbox{実行結果}
	##集計結果表示##
	女性の予想は、[勝ち: 2][引き分け: 2][負け: 1]
	男性の予想は、[勝ち: 1][引き分け: 2][負け: 2]

ホームページ: Yamamoto's laboratory
著者: 山本昌志
Yamamoto Masashi
平成17年6月6日


no counter