11.構造体

11-1. 構造体について
11-2. 代入、複写
11-3. 構造体の宣言をもっと便利に
11-4. 共用体
11-5. ビットフィールド
11-6. 構造体の中の構造体
11-7. 構造体型配列
11-8. 構造体ポインタ
11-9. データチェイン
11-10. エンドレスチェーン
11-11. 構造体と関数
11-12. 構造体そのものを引き渡し
11-13. 構造体へのポインタ引数
11-14. 構造体型の関数
11-15. 構造体ポインタ関数

11-1. 構造体について

◇構造体とは

プログラムの規模が増大していくにつれ変数や配列の管理が大変になります。
これが一人で毎日プログラミングしていてるうちはまだマシなのですが、複数人で開発したり、過去に組んだプログラムを再利用するとなるとこの変数は一体何に使われていたの?という混乱と時間の無駄が発生します。

そこで構造体の登場になります。

簡単に説明すると構造体は複数の変数を一まとめにして扱うものです。
例えば名簿の管理など一人に対して複数の入力項目がある場合、それぞれ変数として定義するより構造体でまとめた方がわかりやすくなります。
文字列や数値など型の違うもの同士ならなおさらです。

name[4] phone[4] email[4] age[4]
┌───┬──────┬────────┬───┐
│鈴木 │090xxxxyyyy │szk@domain.com │ 25 │
├───┼―─────┼────────┼───┤
│佐藤 │090abcdefgh │sto@domain.com │ 32 │
├───┼──────┼────────┼───┤
│田中 │090ijklmnop │tnk@domain.com │ 34 │
├───┼──────┼────────┼───┤
│山本 │090qrstuvwx │ymt@domain.com │ 27 │
└───┴──────┴────────┴───┘

このような管理方法だと電話番号・電子メール別に管理しなくてはならない。

.name .phone .email .age
┌───┬──────┬────────┬───┐
member[0]│鈴木 │090xxxxyyyy │szk@domain.com │ 25 │
├───┼―─────┼────────┼───┤
member[1]│佐藤 │090abcdefgh │sto@domain.com │ 32 │
├───┼──────┼────────┼───┤
member[2]│田中 │090ijklmnop │tnk@domain.com │ 34 │
├───┼──────┼────────┼───┤
member[3]│山本 │090qrstuvwx │ymt@domain.com │ 27 │
└───┴──────┴────────┴───┘

構造体を使えば個人単位で情報をまとめることができます。

◇構造体の宣言

struct 構造体名{
型 メンバ名;
       :
       :
};

・説明
構造体名:構造体の名前をここで定義します。
     この名前を型として変数を宣言します。

メンバ名:構造体に含まれる変数の宣言です。

上の例で構造体を作ってみると

struct list_of_names{
char *name;
char phone[12];
char *email;
int age;
};

struct list_of_names member[4];

また、変数の宣言を構造体の宣言時に行うことができます。

struct list_of_names{
char *name;
char phone[12];
char *email;
int age;
}member[4];

この場合、他にこの構造体型の変数を宣言しない場合は構造体名を省略してもかまいません。

メモリーイメージ
member[0]
+—-+ +—-+
char* 型 | |——–>|鈴木|
|—-+——+ +—-+
char 型 |090xxxxyyyy|
|—-+——+ +—————+
char* 型 | |——–>|szk@domain.com|
|—-+ +—————+
int 型 | 25|
+—-+

member[1]
:
:

◇サンプルプログラム

#include<stdio.h>

struct list_of_names{
        char *name;
        char phone[12];
        char *email;
        int  age;
};

main()
{
    int i;
    struct list_of_names member[4]=
           { {"鈴木","090xxxxyyyy","szk@domain.com",25},
             {"佐藤","090abcdefgh","sto@domain.com",32},
             {"田中","090ijklmnop","tnk@domain.com",34},
             {"山本","090qrstuvwx","ymt@domain.com",27}
           };
    for(i=0;i<=3;i++){
        printf("%s %s ",member[i].name,member[i].phone);
        printf("%s %d\n",member[i].email,member[i].age);
    }
    return 0;
}

/* 結果
鈴木 090xxxxyyyy szk@domain.com 25
佐藤 090abcdefgh sto@domain.com 32
田中 090ijklmnop tnk@domain.com 34
山本 090qrstuvwx ymt@domain.com 27
*/

ここで構造体型変数の初期化とアクセスの仕方を説明します。

◇構造体変数の初期化

変数の配列を初期化するものとして考えていただいて十分です。

たとえば、

struct st_samp{
    int   a;
    int   b;
    char  c;
    float d;
};

ならば、

struct st_samp s1={1,2,’s’,3.0};

のような感じです。名簿の例のようにポインタや配列が含まれていても同じやりかたです。

struct st_samp2{
    int      a;
    int   b[4];
    char  c[8];
    float    d;
};

のときは、

struct st_samp s1={1,{2,3,4,5},”abcdefg”,3.0};

のようになります。

◇メンバへのアクセス方法

構造体メンバへアクセスするためには構造体変数の後にドット(.)をつけてメンバ名を記述します。

構造体変数名.メンバ名

[例] member[0].name