構造体のメンバ

構造体のメンバに、別の構造体を指定することも可能です。構造体が別の構造体を含むことで、データを階層化することができます。

struct
{
    struct { int x, int y } location;
    struct { int width, height } size;
} rect ;

上記のrect変数は、int型の x メンバと y メンバを持つ構造体型のlocationメンバと、同じくint型のwidthメンバとheightメンバを持つ構造体型のsizeメンバを持ちます。rect変数が持つメンバはlocationとsizeメンバの2つだけですが、これらのメンバもまた構造体なのでメンバを持ちます。

rect変数から x メンバや width メンバにアクセスするには、メンバ演算子 . をrect変数のメンバに対しても使います。階層的に、構造体をたどって最終的なメンバにアクセスします。

rect . location . x = 10;

上記のコードは、rect構造体のメンバであるlocation構造体のxに10を代入しています。

構造体型のメンバを持つ構造体の変数を初期化するには、配列型のメンバと同じように初期化子並びを入れ子にします。上のrect変数は、宣言と同時に以下のように初期化できます。

struct
{
    struct { int x, int y } location;
    struct { int width, height } size;
} rect = {
    { 10, 20 },
    { 300, 400 }
};

rect変数に指定している初期化子並びの内側にある2つの初期化子並びが、それぞれlocationメンバとsizeメンバの初期化子となります。この場合、locationメンバの x メンバが10、y メンバが20で初期化されます。同様に、sizeメンバのwidthメンバが300、heightメンバが400で初期化されます。

上の構造体の例は、タグを省略して内容を明記した構造体指定子をメンバ宣言に使用しましたが、一般には、タグを指定して内容を省略した構造体指定子用います。2次元座標を表すPoint構造体と、幅と高さによるサイズを表すSize構造体は、それぞれが独立した値としても機能できます。これらの構造体を再利用して、長方形を表すRectangle構造体を作ると、次のようなコードになります。

struct Point { int x, y; } ;
struct Size { int width, height; } ;
struct Rectangle

{
    struct Point location;
    struct Size size;
} rect ;

上記のコードは、事前に宣言されているPoint構造体とSize構造体をメンバとする Rectangle構造体を作成しています。Point構造体とSize構造体は、Rectangle構造体のメンバとして用いられていますが、それぞれが独立した構造体型として利用することもできます。

Sample05

#include <stdio.h>

int main(void)
{
    struct Point { int x, y; };
    struct Size { int width, height; };
    struct Rectangle {
        struct Point location;
        struct Size size;
    };

    struct Rectangle rect = {
        { 20, 50 }, { 300, 400 }
    };

    printf("x=%d, y=%d, width=%d, height=%d\n",
        rect.location.x, rect.location.y,
        rect.size.width, rect.size.height
    );

    return 0;
}

実行結果

Sample05の実行結果

Sample05は、Point構造体とSize構造体をメンバとして持つRectangle構造体を宣言しています。その後、Rectangle構造体の変数rectを作成し、それぞれのメンバを宣言と同時に初期化しています。printf()関数で、構造体のメンバの値を表示しています。結果を見れば、初期化子に指定した値が正しく設定されていることが確認できます。