またまた・・・・・

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
大工

またまた・・・・・

#1

投稿記事 by 大工 » 18年前

基本的なことですみません・・・^^:

自己参照構造体の質問です><。
struct node_tag{
   int value;
   struct node_tag *next;
}
手持ちの本では「参照先の型が何であろうとも、常にその大きさが決まっているので、構造体メンバの中に自分自身と同じ型のポインタを含めることができるのです。」とありました。

ググってみてもパッとしない理由ばっかりで・・・・struct node_tag next としてはいけない理由は分かるのですが(理由:この時点ではstruct node_tag の大きさがわからないから → 間違ってたらご指摘おねがいします。)派生型(?)だからいいのか? と思うようになりました。

詳しい説明お願いできますでしょうか?


お願いします。m(。。)mペコッ

組木紙織

Re:またまた・・・・・

#2

投稿記事 by 組木紙織 » 18年前

struct node_tag{
   int value;
   struct node_tag *next;
}
の構造体の場合、
[構造体のサイズ] = [intのサイズ] + [構造体へのポインタのサイズ]
となります。
(実際とは違うが、説明の為に単純化していると考えてください。)

intのサイズも、構造体へのポインタのサイズもあらかじめコンパイラは知っているので
構造体のサイズもコンパイラは知ることができ、構造体を作ることができます。
(x = 4 + 2)と同じような感じです。
struct node_tag{
   int value;
   struct node_tag next;
}
ポインタでない場合ですが、
[構造体のサイズ] = [intのサイズ] + [構造体のサイズ]
となります。
この場合は、あらかじめコンパイラが構造体のサイズを知らないのもありますが、
(コンパイラはこの時点でエラーを出す。)
構造体のサイズはどんなに頑張っても出すことはできません。
(x = 4 + x)のxを求めよ。と同じような感じです。

よって構造体のメンバに自分自身を置くことはできない。
となります。

こんな感じの説明しかできませんが分かりますでしょうか?

>派生型(?)
cの内容なので継承の概念はないと思います。この場合はポインタ型と考えるべきだと思います。

大工

Re:またまた・・・・・

#3

投稿記事 by 大工 » 18年前

>intのサイズも、構造体へのポインタのサイズもあらかじめコンパイラは知っているので
>構造体のサイズもコンパイラは知ることができ、構造体を作ることができます。

int型ならまだしも構造体へのポインタのサイズをコンパイラが知っているのが納得いきません><。

構造体は人それぞれが違うものを作るんで大きさは違うはずじゃあ・・・・・・

box

Re:またまた・・・・・

#4

投稿記事 by box » 18年前

sizeof(char *)
sizeof(int *)
sizeof(double *)
sizeof(struct 何とか *)
sizeof(struct かんとか *)
...

これらは、すべて同じです。
「何かの」型を指すポインタ用に確保する領域の大きさは、
その処理系内で不変です。

大工

Re:またまた・・・・・

#5

投稿記事 by 大工 » 18年前

> これらは、すべて同じです。
> 「何かの」型を指すポインタ用に確保する領域の大きさは、
> その処理系内で不変です。


そうだったんですか!!!

解説ありがとうございます。

なぎ

Re:またまた・・・・・

#6

投稿記事 by なぎ » 18年前

既に解決している問題ではありますが……

実はこれは、もう少し込み入った事情があります。
一般的に、再帰的な構造は定義できないのですね。

struct node_tag
{
int value;
struct node_tag next;
};

というのが定義できたと仮定しましょう。(ポインタでなく)

struct node_tag x;
という定義は何を引き起こすでしょうか?

構造体ですから、この時点で、
x.value;
x.next;
という2つのメンバーには(自動的に)アクセス可能となります。
ところが後者は struct node_tag 自身ですから、さらに、
x.next.value;
x.next.next;
というメンバーにも(自動的に)アクセス可能なはずです。

以下、同様にして、
x.next.next.value;
x.next.next.next.value;
x.next.next.next.next.value;
というすべての階層に渡ってアクセス可能であることを保証しなければなりません。
つまり、上記の x のサイズは、「無限大」にならざるを得ないのです

これは、ポインタを経由した場合でも、概念的には
x->next->next->next->next->next->next->next->next->value
などにアクセス可能であることと同様です。
ただし、こちらの場合には、各 next には、プログラム上で領域を確保する必要があります。
つまり、(すべての階層ではなくて)明示的に領域を確保した階層までのアクセスを保証すればいいわけです。

このように、再帰的な構造は必然的に、無制限な階層へのアクセスを求めます。
このため、たとえ、構造体のサイズを事前に決定する方法があったとしても、自分自身をメンバーに含む構造体は定義できないのです。


また、構造体のポインタサイズがあらかじめ決定可能であることは、自己参照だけではなく相互参照も可能にします。


struct typeB;

struct typeA
{
int value;
struct typeB *next;
};

struct typeB
{
int value;
struct typeA *next;
};

のようにお互へのポインタをメンバーとする場合、どちらを先に定義しても、未定義な構造体へのポインタが必要となります。
この場合、最初の struct typeB; のように、構造体のタグ名だけを宣言することができます。
これなど、メンバーの具体的な情報が全くないのに、ポインタは定義できるという例になっています。

大工

Re:またまた・・・・・

#7

投稿記事 by 大工 » 18年前

むむむむ・・・・

こんな深い話があったなんて・・・・

いったいどこでこんな内容を知ったんですか?

なぎ

Re:またまた・・・・・

#8

投稿記事 by なぎ » 18年前

> いったいどこでこんな内容を知ったんですか?

いや、それはわからないんですね。いろいろなところからといいますか、どこだかわからないといいますか。
ただ、時々紹介している、

http://www.kouno.jp/home/c_faq/
(C言語 FAQ)は、何度か通読しています。

あと、どこかの段階で専門書
『プログラミング言語C++』
http://www.bk1.co.jp/product/01597800/
とか、
『Effective C++』
http://www.bk1.co.jp/product/2674464
『C++の設計と進化』
http://www.bk1.co.jp/product/2491914
などを読むのは役に立つと思います。

大工

Re:またまた・・・・・

#9

投稿記事 by 大工 » 18年前

はい!ありがとうございます。

閉鎖

“C言語何でも質問掲示板” へ戻る