問題① 「パディングの調整」の項で見た、構造体の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)
{
("%u %u %u %u %u\n",
printf(struct Data_tag, a),
offsetof(struct Data_tag, b),
offsetof(struct Data_tag, c),
offsetof(struct Data_tag, d),
offsetof(struct Data_tag, e)
offsetof);
("%u %u %u %u %u\n",
printf(struct Data2_tag, d),
offsetof(struct Data2_tag, b),
offsetof(struct Data2_tag, e),
offsetof(struct Data2_tag, c),
offsetof(struct Data2_tag, a)
offsetof);
}
実行結果:
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 {
("%d %d\n", p->x, p->y);
printf= p->next;
p } while (p != head);
}
int main(void)
{
struct Point_tag points[5] = {
{1, 2},
{2, 2},
{3, 4},
{5, 4},
{5, 6}
};
[0].next = &points[3];
points[3].next = &points[2];
points[2].next = &points[4];
points[4].next = &points[1];
points[1].next = &points[0];
points
(&points[0]);
print_points}
実行結果:
1 2
5 4
3 4
5 6
2 2
points[0] を先頭として、0 -> 3 -> 2 -> 4 -> 1 -> 0 とつながるようにしてみました。
確認のために、print_points関数を作ってあります。これは、先頭の点のメモリアドレスを渡すと、そこから点をたどって、座標を出力していくものです。経路は循環しているので、いつか自分自身のところに戻ってきますが、戻ってきたら終わりになるようにしてあります(ヌルポインタが混ざっていたときの対処はしていませんが、してみてもいいでしょう)。
このプログラムのように循環する構造を、循環リストと呼びます。これは、プログラミングをしているとよく登場する典型的な構造の1つです。詳細は、アルゴリズムとデータ構造編【データ構造】第4章で扱っています。
{
の直後と、}
の直前に空白を入れない)()
の前後の空白の空け方)(
の直後、)
の直前に空白を入れない)return 0;
を削除(C言語編全体でのコードの統一) 内容のすべてを第38章へ上書き。この章の内容は完全に新規のものになった。
章のタイトルを変更(「ポインタ⑦(関数ポインタ)」->「ポインタ⑦(構造体とポインタ)」)
第37章の内容をそのままの形で移動して上書き。
全面的に文章を見直し、修正を行った。
章のサブタイトルを変更(高度な使用法 -> 関数ポインタ)
const に関する練習問題①を、第33章へ移動。
「*演算子」を「間接演算子」に統一。
配列の要素数を求めるマクロを、他のページと同じ形の SIZE_OF_ARRAYマクロに統一。
新規作成。
Programming Place Plus のトップページへ
はてなブックマーク に保存 | Pocket に保存 | Facebook でシェア |
X で ポスト/フォロー | LINE で送る | noteで書く |
RSS | 管理者情報 | プライバシーポリシー |