ポインタ⑦(構造体とポインタ) 解答ページ | Programming Place Plus C言語編 第37章

トップページC言語編第37章

問題① 🔗

問題① 「パディングの調整」の項で見た、構造体の2つの形式について、自分の環境では各メンバがどのように配置されるか、offsetofマクロを使って確認してください。


たとえば、次のようなプログラムを書きます。

#include <stddef.h>
#include <stdio.h>

struct Data_tag {
    char   a;
    int    b;
    char   c[20];
    double d;
    short  e;
};

struct Data2_tag {
    double d;
    int    b;
    short  e;
    char   c[20];
    char   a;
};

int main(void)
{
    printf("%u %u %u %u %u\n",
        offsetof(struct Data_tag, a),
        offsetof(struct Data_tag, b),
        offsetof(struct Data_tag, c),
        offsetof(struct Data_tag, d),
        offsetof(struct Data_tag, e)
    );
    printf("%u %u %u %u %u\n",
        offsetof(struct Data2_tag, d),
        offsetof(struct Data2_tag, b),
        offsetof(struct Data2_tag, e),
        offsetof(struct Data2_tag, c),
        offsetof(struct Data2_tag, a)
    );
}

実行結果:

0 4 8 32 40
0 8 12 14 34

問題② 🔗

問題② 2次元上の5つの点を結んで、循環する経路を作りたいと思います。自己参照構造体を使って、このような構造を表現してください。


とりあえず、2次元上の点を表現する構造体型を考えます。x座標と y座標があれば十分でしょう。型の指示は特にないので、int型としておきます。

struct Point_tag {
    int x;
    int y;
};

点は5つあるということなので、この構造体型の変数が5つ、あるいは要素数が5の配列があればよさそうです。たとえば、配列なら次のようにしておけば良いでしょう。

struct Point_tag points[5] = {
    {1, 2},
    {2, 2},
    {3, 4},
    {5, 4},
    {5, 6}
};

さて、問題は循環する経路ということで、自己参照構造体を使えということでした。つまりは、ある点の「次の」点を表現できれば良い訳です。構造体に、「次の点」を表現するポインタを追加します。

struct Point_tag {
    int x;
    int y;
    struct Point_tag* next;
};

next にほかの点のメモリアドレスを格納すれば、次の点をたどれます。5つ目の点の next を1つ目の点を指すようにすれば「循環」させることもできます。

あとは、各点の next を埋めてやります。適当に接続順を決めて試してみます。

#include <stdio.h>

struct Point_tag {
    int x;
    int y;
    struct Point_tag* next;
};

void print_points(const struct Point_tag* head)
{
    const struct Point_tag* p = head;

    do {
        printf("%d %d\n", p->x, p->y);
        p = p->next;
    } while (p != head);
}

int main(void)
{
    struct Point_tag points[5] = {
        {1, 2},
        {2, 2},
        {3, 4},
        {5, 4},
        {5, 6}
    };

    points[0].next = &points[3];
    points[3].next = &points[2];
    points[2].next = &points[4];
    points[4].next = &points[1];
    points[1].next = &points[0];

    print_points(&points[0]);
}

実行結果:

1 2
5 4
3 4
5 6
2 2

points[0] を先頭として、0 -> 3 -> 2 -> 4 -> 1 -> 0 とつながるようにしてみました。

確認のために、print_points関数を作ってあります。これは、先頭の点のメモリアドレスを渡すと、そこから点をたどって、座標を出力していくものです。経路は循環しているので、いつか自分自身のところに戻ってきますが、戻ってきたら終わりになるようにしてあります(ヌルポインタが混ざっていたときの対処はしていませんが、してみてもいいでしょう)。

このプログラムのように循環する構造を、循環リストと呼びます。これは、プログラミングをしているとよく登場する典型的な構造の1つです。詳細は、アルゴリズムとデータ構造編【データ構造】第4章で扱っています。



参考リンク 🔗


更新履歴 🔗

≪さらに古い更新履歴≫

 内容のすべてを第38章へ上書き。この章の内容は完全に新規のものになった。
章のタイトルを変更(「ポインタ⑦(関数ポインタ)」->「ポインタ⑦(構造体とポインタ)」)

 第37章の内容をそのままの形で移動して上書き。

 全面的に文章を見直し、修正を行った。
章のサブタイトルを変更(高度な使用法 -> 関数ポインタ)

 const に関する練習問題①を、第33章へ移動。

 「*演算子」を「間接演算子」に統一。

 配列の要素数を求めるマクロを、他のページと同じ形の SIZE_OF_ARRAYマクロに統一。

 新規作成。



第37章のメインページへ

C言語編のトップページへ

Programming Place Plus のトップページへ



はてなブックマーク に保存 Pocket に保存 Facebook でシェア
X で ポストフォロー LINE で送る noteで書く
rss1.0 取得ボタン RSS 管理者情報 プライバシーポリシー
先頭へ戻る