ポインタ⑦(構造体とポインタ) 解答ページ | Programming Place Plus C言語編 第37章
Programming Place Plus トップページ – 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)
{
( "%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つ目の点とすれば「循環」させることもできます。
配列 points の初期化子の追加はしてもいいですが、しなくても大丈夫です。メンバの個数に対して、初期化子の個数が少ない場合は、不足分はデフォルトの値で初期化がなされます(第26章)。ポインタ型の場合は、ヌルポインタが入るので、いったんそれで構わないでしょう。
あとは、各点の next を埋めてやります。適当に接続順を決めて試してみます。
#include <stdio.h>
struct Point_tag {
int x;
int y;
struct Point_tag* next;
};
void printPoints(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] );
printPoints}
実行結果:
1 2
5 4
3 4
5 6
2 2
points[0] を先頭として、0 -> 3 -> 2 -> 4 -> 1 -> 0 とつながるようにしてみました。
確認のために、printPoints関数を作ってあります。これは、先頭の点のメモリアドレスを渡すと、そこから点をたどって、座標を出力していくものです。経路は循環しているので、いつか自分自身のところに戻ってきますが、戻ってきたら終わりになるようにしてあります(ヌルポインタが混ざっていたときの対処はしていませんが、してみてもいいでしょう)。
このプログラムのように循環する構造を、循環リストと呼びます。これは、プログラミングをしているとよく登場する典型的な構造の1つです。詳細は、アルゴリズムとデータ構造編【データ構造】第4章で扱っています。
return 0;
を削除(C言語編全体でのコードの統一)’2018/6/1 内容のすべてを第38章へ上書き。この章の内容は完全に新規のものになった。
章のタイトルを変更(「ポインタ⑦(関数ポインタ)」->「ポインタ⑦(構造体とポインタ)」)
’2018/5/31 第37章の内容をそのままの形で移動して上書き。
’2018/3/13 全面的に文章を見直し、修正を行った。
章のサブタイトルを変更(高度な使用法 -> 関数ポインタ)
’2018/3/9 const に関する練習問題①を、第33章へ移動。
≪さらに古い更新履歴を展開する≫
Programming Place Plus のトップページへ