C言語

異なる種類の変数をまとめることができる構造体の使い方

これまで、複数の値をまとめて扱いたい場合、配列を使ってたくさんのデータを扱いました。ただ、この配列は同じ変数名に[ ]が付いたものでした。これだと、同じ意味のデータが複数扱えるだけです。
もっと違うデータも複数扱いたい場合があると思います。例えば、生徒の名簿だと、学年、クラス、出席番号、氏名が100人分ほしい場合、学年の変数、クラスの変数、出席番号の変数、氏名の変数をそれぞれ配列として100個用意する必要があります。名前に至っては、1人分でも配列を用意する必要があり、それを100人分だと、2次元配列にする必要もあります。また、変数が別々に用意されていると、1人のデータの関連性がなく、わかりにくくなってしまいます。

このような場合に、複数の意味の異なる変数を1つにまとめる方法として、構造体という機能が用意されています。

今回は、この構造体について学んでいきたいと思います。

構造体の仕組み

構造体は、複数の異なる型の値をまとめた新しい型のことをいいます。この新しい型のことを構造体型と呼びます。
構造体を使用するには、この構造体型がどのような型が集まったものなのかを取り決める必要があります。これを構造体型の宣言といいます。
次に、構造体型の宣言の構文を示します。

構造体型の宣言

struct 構造体型名
{
型名 識別子 ;
型名 識別子 ;
   :
   :
} ;

構造体型を宣言するときは、 struct を付けます。
構造体型名は、変数などの識別子と同様で、半角英数字とアンダースコアが使用可能で、自由に付けることができます。
そして、{ } で囲んだブロック内は、変数宣言と同様に、型名と変数名を記述します。異なる型でも、配列でも問題ありません。
ブロックの最後は、セミコロン( ; )を付けます。
構造体型の宣言は、以上です。

構造体型を宣言した例を次に示します。

struct school
{
    int year;      /* 学年 */
    int clas;      /* クラス */
    int number;    /* 出席番号 */
    char name[32]; /* 名前 */
};

ただし、ここでは、使用する型を定義したのみで、実際に変数宣言をしたわけではないため、このままでは使用することができません。

構造体変数を宣言する

構造体型を定義したあと、実際に構造体型の変数を宣言するには、次のように記述します。

構造体変数の宣言

struct 構造体型名 構造体変数名 ;

構造体型の変数を宣言した例を次に示します。

struct school studentData;

このように定義することにより、school型の構造体の変数であるstudent_dataが使用可能になります。

構造体型の変数は、同じ構造体の型同士の代入はできますが、演算や比較には使用できません。

構造体型の変数の使い方

構造体型の変数を宣言すると、その中に定義した変数に値を格納できるようになります。
配列のときは、同じ変数名を番号によって区別していましたが、構造体型の変数の場合は、構造体型の中に定義した変数名で区別します。
構造体型の中に定義した変数名のことをメンバと呼び、このメンバを利用するためには、ドット演算子( . )を使用します。ドット演算子は、見にくいですが、小数点記号です。カンマではありません。
構造体型の中に定義した変数にアクセスするには次のように記述します。

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

構造体型変数名.メンバ

構造体型の変数に値を代入した例を次に示します。

studentData.year = 1;
studentData.clas = 2;
studentData.number = 5;

次に、構造体型の定義から構造体型のメンバへのアクセスサンプルプログラムを示します。

#include <stdio.h>

struct school
{
    int year;      /* 学年 */
    int clas;      /* クラス */
    int number;    /* 出席番号 */
    char name[32]; /* 氏名 */
};

int main(void)
{
    struct school studentData;

    studentData.year = 1;
    studentData.clas = 2;
    studentData.number = 5;
    studentData.name[0] = 'b'
    studentData.name[0] = 'i'
    studentData.name[0] = 's'
    studentData.name[0] = 'e'
    studentData.name[0] = 'n'

    printf("学年:%d年\n", studentData.year);
    printf("クラス:%d組\n", studentData.clas);
    printf("出席番号:%d\n", studentData.number);
    printf("指名:%s\n", studentData.name);

    return 0;
}

サンプルプログラムの実行結果は次のようになります。

実行結果

学年:1年
クラス:2組
出席番号:5
氏名:bisen

構造体の初期化

構造体の初期化は、配列の初期化と同様に、宣言と同時に値を代入できます。

構文

構造体型 構造体変数名 = { 値 , 値, ・・・ } ;

{ } で囲んだ中に、定義したメンバの順番に、左からカンマ( , )で区切って、値を並べて記述します。
構造体を初期化して表示するサンプルプログラムを次に示します。

#include <stdio.h>

struct school
{
    int year;      /* 学年 */
    int clas;      /* クラス */
    int number;    /* 出席番号 */
    char name[32]; /* 氏名 */
};

int main(void)
{
    int i;
    struct school studentData = { 3, 2, 1, "yamada" };

    printf("学年:%d年\n", studentData.year);
    printf("クラス:%d組\n", studentData.clas);
    printf("出席番号:%d\n", studentData.number);
    printf("指名:%s\n", studentData.name);

    return 0;
}

実行結果は、次のようになります。

実行結果

学年:3年
クラス:2組
出席番号:1
指名:yamada

構造体の初期化では、構造体変数の全体を0で初期化する場合は、次のように記述することで、全体を0クリアできます。

struct school studentData = {0};

{ 0 }と記述することで、すべてのメンバが0クリアされます。

構造体の使い方は以上ですが、構造体も変数と同様に配列にすることができますので、少し触れたいと思います。

構造体型の変数の配列の宣言は次のようにします。

構造体変数配列の宣言

struct 構造体型名 構造体変数名[要素数] ;

使い方はこれまでの配列と同じようにできます。

構造体変数配列へのアクセス

構造体型変数名[添字].メンバ

メンバがあるので、これまでの配列とは違う感じがしますが、 変数名を指定して、[ ] の中に要素数を指定するのは同じです。そして、その変数毎にメンバへアクセスするという形になります。

構造体型変数配列を使ったサンプルプログラムを次に示します。

#include <stdio.h>

struct school
{
    int year;      /* 学年 */
    int clas;      /* クラス */
    int number;    /* 出席番号 */
    char name[32]; /* 氏名 */
};

int main(void)
{
    int i;
    struct school studentData[2] = {
    { 3, 2, 1, "yamada" },
    { 3, 2, 2, "hanako" }};

    for( i = 0; i < 2; i++ )
    {
        printf("学年:%d年\n", studentData[i].year);
        printf("クラス:%d組\n", studentData[i].clas);
        printf("出席番号:%d\n", studentData[i].number);
        printf("指名:%s\n", studentData[i].name);
    }

    return 0;
}

構造体型変数の初期化は、配列と同様に、{ } で記述します。{ } の中の { } は、1つの構造体型変数の初期化です。
構造体型の変数を2つ用意した形になっています。これを初期化して、for文ですべて画面に表示ています。

サンプルプログラムの実行結果は次のようになります。

実行結果

学年:3年
クラス:2組
出席番号:1
指名:yamada
学年:3年
クラス:2組
出席番号:2
指名:hanako

以上が、構造体の使い方でした。

構造体型の名称をtypedefで変更

構造体型の変数を宣言するときに、structを付ける必要がありました。ただ、宣言する度にstructをつけなければならないのは不便です。そのため、structを省略できるように、C言語では、新しい型を宣言するための、typedef(タイプデフ)というものが用意されています。
typedefは、すでに存在している型に対して、新しい名前をつけるための、キーワードです。

typedefの構文

typedef 型名 識別子;

構造体型に使用する場合は、次のように書くことが多いです。

typedef struct school {
    int year;      /* 学年 */
    int clas;      /* クラス */
    int number;    /* 出席番号 */
    char name[32]; /* 氏名 */
} school;

typedefのあとに、構造体型名のstruct schoolを記述し、構造体型を宣言します。構造体型の宣言をした後、} の後に、新しい型名のschoolを付け、最後に、セミコロンで完了です。
このようにすることで、この後、構造体型変数名の宣言時は、schoolという型で宣言ができます。

school studentData;

typedefで、struct schoolをschoolという新しい型名を付けたため、これで、school型として使用できるようになります。

以上が、構造体の使い方についてでした。

次は、ポインタの仕組みについてです。

ポインタの仕組み

-C言語