納得C言語
[第15回]演習問題Ⅳ 第1問
第14回まで学習した内容を使い、演習問題を行います!
1 社員給与表を作ってみよう
下の表をscanf( )を使って構造体に格納して表示させてみよう
ただし、社員番号の入力で0を入力したら入力を終了し、データを表示させるようにします
結果のようになればOK!!
結果
演習問題Ⅳ 第1問のヒント
1 社員給与表を作ってみよう
1.文字を入力させるところ以外は第14回の練習問題Ⅲの(1)と似ているので、作ったプログラムを思い出してみよう
2.構造体の型宣言で文字列をポインタで宣言すると実行中にエラーが生じるので、文字配列で宣言します
3.入力終了判定は社員番号入力後がいいでしょう。そうすることで無駄な入力を省くことができます
演習問題Ⅳ 第1問の解答
1 社員給与表を作ってみよう
解答プログラム
#include <stdio.h> // 構造体(3か月分の給与) struct kyuyo { int kyu_apl; // 4月分 int kyu_mar; // 5月分 int kyu_jun; // 6月分 }; // 構造体(社員) struct shain { int no; // 社員番号 char name[256]; // 社員名 char busyo[256]; // 部署名 char fp[256]; // 役職 struct kyuyo money; // 給与(構造体) }; int main() { int i = 0; // 構造体の宣言(配列) struct shain list[256]; // 構造体ポインタの宣言 struct shain *p; // ポインタにlist構造体の先頭アドレスを代入 p = list; while(1){ // 構造体にデータを入力 printf("社員番号:"); scanf("%d",&(p+i)->no); // 社員番号に0が入力されたら終了 if((p+i)->no==0){ break; } printf("社員名:"); scanf("%s",(p+i)->name); printf("部署:"); scanf("%s",(p+i)->busyo); printf("役職:"); scanf("%s",(p+i)->fp); printf("給与\n"); printf("4 月:"); scanf("%d",&(p+i)->money.kyu_apl); printf("5月:"); scanf("%d",&(p+i)->money.kyu_mar); printf("6月:"); scanf("%d",&(p+i)->money.kyu_jun); i++; printf("\n"); } // 入力されたデータの表示 printf(" 給与\n"); printf("社員番号 氏名 部署 役職 4月 5月 6月\n"); for(i=0;(p+i)->no!=0;i++){ printf("%8d%10s%8s%6s%9d%9d%9d\n", (p+i)->no, (p+i)->name, (p+i)->busyo, (p+i)->fp, (p+i)->money.kyu_apl, (p+i)->money.kyu_mar, (p+i)->money.kyu_jun ); } return 0; }
解説
まず、4~6月分の給与を格納する構造体の型を宣言します。
次に、社員情報を格納する構造体の型を宣言します。
このとき、給与の構造体の型宣言は、社員情報の構造体宣言より先に行わなくてはなりません。
次に、社員情報構造体の宣言と、その構造体へのポインタを宣言し、アドレスを渡してあげます。
社員情報を格納していくときは、人数がわからない場合が多いので無限ループで0が入力されたら終了としておきましょう。
また、無限ループを抜けるタイミングは社員番号が入力されたら判別するようにすれば楽になります。
表示は例題と同じですね。
今回は構造体の入れ子というちょっと応用的な問題になりました。
構造体の構造体をポインタで呼び出すときやりがちなミスとして
(p+i)->money->kyu_apl
と書いてしまうかもしれません。
しかし、kyuyo構造体へのポインタはないので、kyuyo構造体の参照はドット演算子( . )を使用します。
演習問題Ⅳ 第2問
第14回まで学習した内容を使い、演習問題を行います!
2 社員の平均給与
(1)で格納したデータで1人あたりの4月~6月の給与の平均を求める自作関数を作ってみよう。
結果のようになればOK!!
結果
演習問題Ⅳ 第2問のヒント
2 社員の平均給与
1.自作関数で入力したデータの構造体を使いたい時は参照渡しを使って関数に渡します
2.自作関数で構造体を読み出す時は、ポインタを用いているのでアロー演算子を使います
演習問題Ⅳ 第2問の解答
2 社員の平均給与
解答プログラム
#include <stdio.h> // 構造体(3か月分の給与) struct kyuyo { int kyu_apl; // 4月分 int kyu_mar; // 5月分 int kyu_jun; // 6月分 }; // 構造体(社員) struct shain { int no; // 社員番号 char name[256]; // 社員名 char busyo[256]; // 部署名 char fp[256]; // 役職 struct kyuyo money; // 給与(構造体) }; // 関数のプロトタイプ宣言 void money_avg(struct shain *p); int main() { int i = 0; struct shain list[256]; struct shain *p; p = list; //社員データ入力 //説明は (1)でやっているので省略します while(1){ printf("社員番号:"); scanf("%d",&(p+i)->no); if((p+i)->no==0){ break; } printf("社員名:"); scanf("%s",(p+i)->name); printf("部署:"); scanf("%s",(p+i)->busyo); printf("役職:"); scanf("%s",(p+i)->fp); printf("給与\n"); printf("4 月:"); scanf("%d",&(p+i)->money.kyu_apl); printf("5月:"); scanf("%d",&(p+i)->money.kyu_mar); printf("6月:"); scanf("%d",&(p+i)->money.kyu_jun); i++; printf("\n"); } //社員表表示 //説明は省略 printf(" 給与\n"); printf("社員番号 氏名 部署 役職 4月 5月 6月\n"); for(i=0;(p+i)->no!=0;i++) { printf("%8d%11s%8s%6s%10d%10d%10d\n", (p+i)->no, (p+i)->name, (p+i)->busyo, (p+i)->fp, (p+i)->money.kyu_apl, (p+i)->money.kyu_mar, (p+i)->money.kyu_jun ); } money_avg(p); return 0; } //各社員の平均給与 void money_avg(struct shain *p) { int sum=0,i=0; printf("\n社員ごとの平均給与\n"); //(p+i)->noがになるまで続ける while((p+i)->no!=0){ //sumに,5,6月分の給与を格納 sum = (p+i)->money.kyu_apl + (p+i)->money.kyu_mar + (p+i)->money.kyu_jun; //平均を表示 //このとき直接計算式を書いてもOKです printf("%8s\t%6d\n",(p+i)->name,sum/3); //sumの初期化 sum=0; i++; } printf("終了"); }
解説
入力と表示は(1)と同じですね。
社員の平均ということで、今回は自作関数内で計算し、表示を行っています。
変数sumに4,5,6月分の給与を代入し、printfで表示させています。
printf内で計算を行っていますが、表示されるときは計算された結果が出力されます。
これを、while文で社員番号が0になるまで繰り返します。
演習問題Ⅳ 第3問
第14回まで学習した内容を使い、演習問題を行います!
3 役職ごとの平均給与
(1)で格納したデータで、役職ごとの給与の平均を求める自作関数を作ってみよう(やや難)
結果
演習問題Ⅳ 第3問のヒント
3 役職ごとの平均給与
1.自作関数で入力したデータの構造体を使いたい時は参照渡しを使って関数に渡します
2.役職ごとの平均を求めるには、全ての役職名を抜き出す必要があります。抜き出した役職名を基に平均を出していきます。抜き出す方法は各自出来る方法を用いるといいでしょう。さらにどの役職に何人いるかというのも出しておく必要があります。
演習問題Ⅳ 第3問の解答
3 役職ごとの平均給与
解答プログラム
//プログラムを書くときには「①,②,③」は書かないでください #include <stdio.h> #include <string.h> // 構造体(3か月分の給与) struct kyuyo { int kyu_apl; // 4月分 int kyu_mar; // 5月分 int kyu_jun; // 6月分 }; // 構造体(社員) struct shain { int no; // 社員番号 char name[256]; // 社員名 char busyo[256]; // 部署名 char fp[256]; // 役職 struct kyuyo money; // 給与(構造体) }; // 関数のプロトタイプ宣言 void fp_avg(struct shain *p); int main() { int i = 0; struct shain list[256]; struct shain *p; p = list; //社員データ入力 //説明は (1)でやっているので省略します while(1){ printf("社員番号:"); scanf("%d",&(p+i)->no); if((p+i)->no==0){ break; } printf("社員名:"); scanf("%s",(p+i)->name); printf("部署:"); scanf("%s",(p+i)->busyo); printf("役職:"); scanf("%s",(p+i)->fp); printf("給与\n"); printf("4 月:"); scanf("%d",&(p+i)->money.kyu_apl); printf("5月:"); scanf("%d",&(p+i)->money.kyu_mar); printf("6月:"); scanf("%d",&(p+i)->money.kyu_jun); i++; printf("\n"); } //社員表表示 //説明は省略 printf(" 給与\n"); printf("社員番号 氏名 部署 役職 4月 5月 6月\n"); for(i=0;(p+i)->no!=0;i++){ printf("%8d%11s%8s%6s%10d%10d%10d\n", (p+i)->no, (p+i)->name, (p+i)->busyo, (p+i)->fp, (p+i)->money.kyu_apl, (p+i)->money.kyu_mar, (p+i)->money.kyu_jun ); } fp_avg(p); return 0; } //役職ごとの3ヶ月平均給与 void fp_avg(struct shain *p) { int sum=0; //合計用 int i=0; //ポインタ用 int j=0; //人数カウント用 char *str; //str に1人目の役職をコピー ①str = p->fp; printf("\n役職ごとの3ヶ月の平均給与\n"); //(p+i)->noが0になるまで繰り返す while(((p+i)->no)!=0){ //strと(p+i)->fpを比較し同じ役職であれば繰り返す while(②strcmp(str,(p+i)->fp)==0){ //sumに現在の社員の給与を格納(この時sum自身も加算します) sum = sum + (p+i)->money.kyu_apl + (p+i)->money.kyu_mar + (p+i)->money.kyu_jun; //ポインタを一つ進める i++; //人数をカウント j++; } //役職の平均給与を算出し表示 printf(" 役職 給与額\n"); printf("%6s %10d\n",str,sum/(j*3)); ③//人数と合計をで初期化 j=0; sum=0; //strを初期化し次の役職を格納する str = ""; str = (p+i)->fp; } }
解説
社員データの入力と表示は第1問、第2問と同じですね。
自作関数内の説明に入ります。
①で1人目の役職をstrに格納します。
まず「部長」がstrに格納されますね。
②ではstrと(p+i)->noの比較をしています。
このときiは0なので(p+0)->noとstrを比較。
「部長」で同じなのでwhile文の中を実行します。
sumにsumとその社員の3ヶ月分の給与を代入します。
また、iとjの値に1加算します。
そして再びstrcmpで比較します。
まだ部長で同じですね。
なので、sumにsumと2人目の社員の給与を代入します。
iとjが3まできました。
③)で比較をすると、strは部長ですが、(p+3)->fpは課長ですね。
なので今回でwhile文から抜け出します。
抜け出したあと、strの役職の平均給与を計算し、表示しています。
このままではjにこれまでの人数が、strに前の役職が格納されたままなので、網掛けの部分で初期化します。
初期化されると下のようになります
strに課長、jに0が格納されましたね。
これを、社員番号が0になるまで繰り返します。
このくらいのプログラムが書けるようになれば、C言語を理解できたといえるでしょう
あとがき
C言語の学習の方は順調でしょうか?
今回はC言語で最も難しいと言われているポインタと構造体の学習を行いました。
ポインタや構造体は理解するのに時間がかかりますが、使いこなすことが出来ると本当に便利です。
正直、今回の学習ではポインタや構造体の全てを語りきることが出来ませんでした。
この学習を終えて、ポインタや構造体をもう少し詳しく知りたいと思った時にさらに深いところまで調べるといいでしょう。
今よりさらなる壁が立ちはだかりますが、それを乗り越えた時には間違いなくC言語の知識を身に付けたと実感しますよ。
さて、次回はいよいよ最終回です。
ここまでたどり着いたあなたならもう怖いものなしでしょう。
コメントの投稿
トラックバックURL
http://www.isl.ne.jp/cgi-bin/mt/mt-tb.cgi/1103