第14回:構造体

 今週は,構造体を学びます.

 配列は同じ型のデータをまとめて扱う手段でした.では,異なる型はまとめて扱うことはできないのでしょうか.

 たとえば,みんなのレポート提出状況をチェックするえんま帳を例にとると,

学年
番号
氏名
1回目
2回目
平均
成績
2
1
1
アベ
50
70
60.0
B
2
1
2
イトウ
80
60
70.0
B

 データは,学年や各回の点数が整数型,氏名が文字列型,平均点が浮動小数点型となっていて,一つの配列で取り扱うことができないようです.

 そこで,異なる型のデータをまとめて扱うための手段として,構造体を用います.


構造体の宣言

 構造体を利用するには,異なった型をまとめて一つの構造体(一種の型)を定義します.

 構造体の定義は,次の二つのステップで行います.

  1. 構造体テンプレートの宣言:どのような方の変数をまとめるかを記述する
  2. 構造体変数の宣言:構造体テンプレートに従った,変数を定義する

 では,実際の例を見てみましょう.

構造体テンプレートの宣言

struct seiseki{
    int gakunen;
    int kumi;
    int bangou;
    char simei[25];
    int ten_1;
    int ten_2;
    float heikin;
    char seiseki;
};

構造体変数の宣言

struct seiseki list2002;

 変数の定義と同時に初期化したいときは...

struct seiseki list2002 = {2,1,1, "アベ",10,20,0,'A'};
 構造体の要素一つ一つのことをメンバと呼びます.メンバを利用する方法を見てみましょう.
printf("%d %s %f\n", list2002.bangou, list2002.simei, list2002.heikin);

 メンバへ値を代入するときも同様です.

list2002.bangou = 3;
list2002.simei = "ウエダ";

構造体とポインタ

 変数のポインタと同じように,構造体のポインタというのもあります.頭が混乱しそうですが,よく整理して理解しましょう.

struct seiseki{
    int gakunen;
    int kumi;
    int bangou;
    char simei[25];
    int ten_1;
    int ten_2;
    float heikin;
    char seiseki;
};
struct seiseki list1;
struct seiseki *kp;

kp = &list1;

となります.

ポインタを用いるとき,構造体の各要素はどのように表されるのでしょうか?ポインタの中身を参照するには,

int *p;

と宣言した場合は,

*p

でしたね.では構造体だと,

struct seiseki *kp;

と定義すると要素は,

*kp.gakunen

で良いでしょうか?これでは,コンパイラのエラーになってしまいます.正確には,

(*kp).gakunen

と書きます.ちょっと面倒なので,C言語ではこれをアロー演算子を用いて

kp->gakunen

と書きます.

#include <stdio.h>

struct seiseki{
    int gakunen;
    int kumi;
    int bangou;
    char simei[25];
    int ten_1;
    int ten_2;
    float heikin;
    char seiseki;
};

void main()
{
    struct seiseki list2, *sp;

    sp = &list2;

    sp->gakunen = 2;
    sp->kumi = 1;

    printf("%d年%d組\n", sp->gakunen, sp->kumi);
}

構造体の配列

 通常の変数と同じように,定義した構造体変数についても配列を考えられ,構造体配列と呼びます.

struct seiseki list2[10];

 初期化するなら,

struct seiseki list2[10] = {
    {2,1,1, "アベ",10,20,0,},
    {2,1,2, "イトウ",5,10,0,},
};

構造体配列の要素を参照する方法には,三つあります.

[ ] を使う
int i;
for(i=0; i<10; i++)
  printf("%d年%d組\n", list2[i].gakunen, list2[i].kumi);
* を使う
int i;
struct seiseki *sp;
sp = list2; /* 構造体の配列名は,要素0番のアドレスなので & はいらない */
for(i=0; i<10; i++)
  printf("%d年%d組\n", *(sp+i).gakunen, *(sp+i).kumi);
-> を使う
int i;
struct seiseki *sp;
for(sp = list2; sp != list2+10; sp++)
  printf("%d年%d組\n", sp->gakunen, sp->kumi);

参考:文字列の代入

 文字列は,変数に直接代入することができません.

char name[20];

name = "kobayashi";

これは,エラーになります.では,どうやって文字列に代入するかというと,

char name[20];

name[0] = 'k';
name[1] = 'o';
....

と,とても大変です.そこで,文字列の代入をする関数が用意されています.

#include <string.h>

char name[20];

strcpy(name, "kobayashi");

【演習】

 下記の成績データをファイルから読み込んで,各学生の2回のテストの平均点を計算し,成績を判定するプログラムを,構造体を用いて作成せよ.

2,1,1,アベ,50,60
2,1,2,イトウ,70,45
2,1,3,ウエダ,90,53
2,1,4,エンドウ,75,65
2,1,5,オカダ,30,15
2,1,6,カトウ,90,76
2,1,7,キダ,80,56
2,1,8,クリタ,86,95

成績対応表
A
80点以上
B
60点以上
C
50点以上
F
50点未満
ステップ1
まずは,構造体を使わずに,データを読み込んで画面に表示するだけのプログラムを作ってみる.
ステップ2
変数を構造体を用いるように変更する.
ステップ3
構造体の配列を用いる
ステップ4
平均点を求める部分を関数にし,メイン関数から引数として構造体ポインタを用いて渡し,平均点を計算して構造体の平均に代入するようにする.