10日目 12日目

11日目

目標


課題11

構造体

ある授業の受講者に関する情報を取り扱うようなプログラムを考えるとしよう。 取り扱う情報としては、「学籍番号」、「姓」、「名」、 「講義への出席回数」、「テストの点数」を考える。 課題11では、このような情報をプログラム上でうまく取り扱う方法について取りあげる。

一番原始的な方法としては、

        /* 一人目 */
        char gakuseki_bango_01[10];
	char family_name_01[40];
	char given_name_01[40];
	int  shusseki_01;
	int  mark_01;

        /* 二人目 */
        char gakuseki_bango_02[10];
	char family_name_02[40];
	char given_name_02[40];
	int  shusseki_02;
	int  mark_02;

のように、すべてについて個別に変数を用意する方法が考えられる。 しかし、これではプログラムの可読性も低下するし、そもそも手間がかかって仕方がない。

このような場合には、配列を使えば良かったのであった。 そこで、配列を使って宣言すると次のようになる。 たとえば受講生が最大30人であるという事があらかじめ判っているとして、 配列を使って宣言を行うと、次のようになる。

        char gakuseki_bango[30][10];
	char family_name[30][40];
	char given_name[30][40];
	int  shusseki[30];
	int  mark[30];

しかし、これでも、ある受講生の情報が様々な配列にバラバラに格納されることになり、 扱いやすいとは言いがたい。たとえば、一人一人の学生の情報を入力するような 関数を考えた場合、引数として5つの変数を渡さなければならない。

このような複数の型をまとめて扱いたいような場合、 C 言語では、複数のデータをひとまとめにして扱う「構造体(structure)」という データ型を使用することができる。

構造体を使用するためには、最初にどのようなデータを含む構造体なのかを宣言する必要がある。 宣言は structを用いて

struct student_info {
      char gakuseki_bango[10];
      char family_name[40];
      char given_name[40];
      int shusseki;
      int mark;
};

のように行う。student_info はタグと呼ばれ、構造体の型についた名前のようなものである。 (宣言と同時に変数も宣言してしまうような場合には、タグは省略することも可能。) {} でくくられた中に宣言された変数は「メンバ」と呼ばれる。 この宣言により、student_infoという構造体の構成が定義されたので、 これ以降 student_info「型」の変数は、次のような宣言で使用することができる。

  struct student_info info;
  struct student_info data[40];
  struct student_info *pdata;

dataは、構造体の配列の宣言の例であり、pdataは構造体のポインタの宣言の例である。

構造体の宣言と変数の宣言を同時にすることもできる。

struct student_info {
      char gakuseki_bango[10];
      char family_name[40];
      char given_name[40];
      int shusseki;
      int mark;
} info, data[40], *pdata;

構造体の初期化の際には、次のようにして値をセットすることができる。

   struct student_info info = {
       "08913765",
       "大垣内",
       "多徳",
       13,
       65
   };

しかし、初期化以外の場面ではこの手法は取れず、値を設定するためには、 メンバーごとに行う必要がある。ただし、同じ型の構造体変数からの代入は可能である。

構造体の各メンバーへのアクセスは.演算子を用いる。 各メンバーはその型に可能な行為はすべて許される。

    strcpy(info.gakuseki_bango, "08913765");
    strcpy(info.family_name, "大垣内");
    strcpy(info.given_name, "多徳");
    info.shusseki = 13;
    info.mark     = 65;

構造体が、ポインタ変数であった場合、"*" 演算子よりも、"."演算子の優先順位が高いため、 (*pdata).shussekiのように必ず "()" が必要である。 いちいち "()" をつけるのは煩雑なので、その短縮形として padta->shussekiという 形式を使うことができる。

strcpy関数は、第二引数で与えられる文字列(char 型のポインタであった)の 内容を、第一引数で与えられるポインタにコピーする。 コピー先の大きさに関するチェックは行われないので、注意すること。 特に文字列には、終端文字が含まれる為に「目に見える」長さより1バイト多く必要である事に留意する。 コピーする文字列の長さを制限するstrncpyなどもある。


問題 11

ある講義の受講生のデータとして次のような書式の ~tacha/kadai11/dataを用意した。 このファイルは一行が一人の学生を表しており、それぞれ、学籍番号、姓、名、出席回数、テストの点数が書かれているものとする。

101219 赤松 将明    12 67
129529 小泉 恒三郎  9  77
132979 細田 章生    9  45
191646 永田 大和    10 70
198622 江田 利勝    10 98
217691 逢沢 正志    13 19
233260 武部 圭朗    9  23
241497 杉田 康弘    9  28
289740 上野 忠彦    13 99
290975 長浜 教嚴    11 58
337877 嘉数 正忠    10 80
348560 小沢 茂樹    11 29
351722 塩崎 孝弘    11 56
387218 土屋 英一郎  14 83
390102 大串 健嗣    11 92
458131 原口 宜伸    12 26
495343 福島 律夫    10 39
559234 伴野 政賢    8  94
651989 市村 章宏    11 76
672924 篠田 匠      10 53
  1. このファイルを読み込み、テストの点数に加えて出席回数1回につき 2点与えたものを総合得点として計算し、 各人の学籍番号、姓名、総合得点を表示するプログラムを作成せよ。

  2. 総合得点の最高点、最低点を求め、該当する受講生の情報を表示するように改良せよ。

  3. 学籍番号、姓名、総合得点を総合得点の高い順に表示できるように改良せよ。 整列の手法が不明な場合にはバブルソートを用いよ。


10日目 表紙 12日目

tacha@tack.fukui-med.ac.jp
$Id$