11.構造体

11-8. 構造体ポインタ

◇構造体ポインタ

 今回説明する構造体ポインタは「構造体へのポインタ」を意味します。
つまり、定義した構造体をポインタとして宣言します。

プログラム例:

#include<stdio.h>

struct st_samp{
    int i,j;
    char c;
};

main()
{
    struct st_samp s1={1,2,'A'};
    struct st_samp *p_st=&s1;
    
    printf("i=%d,j=%d,c=%c",(*p_st).i,(*p_st).j,(*p_st).c);
    return;
}

結果:
i=1,j=2,c=A
と表示されますが、プログラミングするときの注意点が2つあります。

1.構造体ポインタだけではだめ。
*p_stはあくまでポインタであって構造体そのものではありません。
そして、構造体も定義しただけでは実体をもたないのでどれかひとつは宣言しておかないとポインタが指すものがありません。
(ポインタなら極当たり前のことですけど・・・)

2.書式に注意
今回、アクセスするとき(*p_st).iのようにしました。
これを*p_st.iとしたら文法エラーになります。
もちろんポインタはメンバを持たないからです。
ちなみに*p_st.iは違う意味になります。
(構造体p_stのメンバポインタiが指すもの)
ということでこれらの違いをよく理解しておいてください。

また、(*p_st).iの代わりに次の書式も使えます。

 p_st->i

(*p_st).iとまったく同じ意味になります。
これで、->という矢印のような記号の意味が解けたと思います。

それでは
stmain.p_stsub->member

としたらどうでしょう。想像つきますか?

プログラム例:

#include<stdio.h>

struct st_sub{
    int member;
};

struct st_main{
    struct st_sub *p_stsub;
};

main()
{
    struct st_sub s1={1};
    struct st_main stmain={NULL};
        stmain.p_stsub=&s1;
    printf("member=%d\n",stmain.p_stsub->member);
    return;
}

結果:
member=1

このような感じで結構です。
ちなみにメンバの初期化では変数などが使えなかったのでとりあえずNULLで初期化してみました。(この場合、初期化そのものの意味がないのですが…)

もし、他のメンバが存在していてそのメンバの初期化が必要ならメンバポインタの部分だけNULL等で初期化して、その直後にアドレスを代入すれば良いと思います。

◇構造体ポインタの演算

今度は構造体ポインタをインクリメントしてアクセスしてみます。

#include<stdio.h>

struct st_samp{
    int i,j;
};

main()
{
    int i;
    struct st_samp s1[4]={1,2,3,4,5,6,7,8};
    struct st_samp *p_st=s1;
    for(i=0;i<4;i++){
        printf("i=%d j=%d\n", p_st->i, p_st->j);
        p_st++;
    }
    return;
}

結果:
i=1 j=2
i=3 j=4
i=5 j=6
i=7 j=8

このように構造体ポインタをインクリメントすると、構造体の大きさだけアドレスが進みます。

p_st s1[4]
+——–+ +————-+
| |-+–>| |
+——–+ | | |
| +————-+
+–>| |
| | |
| +————-+
+–>| |
| | |
| +————-+
+–>| |
| |
+————-+