0

C では、以下が有効です。

int a[] = {27,2};
int *b;
int c;

b = a;
c = *b; /* c == 27 */

ポイントは、a は配列の単なるアドレスであるため、ポインターに割り当てることができるということです。構造体についても同じことが当てはまらないのはなぜですか。構造体変数の値は単なるアドレスであるため、次のようにポインターに割り当てることができるはずです。

struct foo bar;
struct foo *doo;
bar.x = 0;
doo = bar; //is this legal?
doo.x = 0; //why can't I use the dot?

言い換えれば、構造体変数の値が最初のコンポーネントのアドレスである場合 (これは配列のような場合だと思います)、上記のコードは有効です。

4

6 に答える 6

3

ポイントはa、配列のアドレスであるため、ポインターに割り当てることができるということです。

これは正しくありません。コンパイラは、配列の名前を、配列の最初の要素を指すポインターに変換します。これは、キャストや「アドレス」演算子を必要とせずに自動的に行われます&。しかし、aはアドレスだけではありませんsizeof(a)

これは、同じことが当てはまらない理由を説明するはずですstruct(つまり、配列には当てはまらないため)。s の場合struct、"address of" 演算子&は必須です。

doo = &bar;

ドゥー.x = 0; // ドットを使用できないのはなぜですか?

C には、ポインターを介して s 要素にアクセスするための別の構文があります。ドット演算子の代わりに演算子structを使用する必要があります。->.

于 2013-02-12T21:24:39.160 に答える
2

他の人が指摘したように、配列のセマンティクスは構造体のセマンティクスとは異なります。その理由については、C が以前の言語 ( BCPLおよびB )から派生したことを覚えておく必要があります。どちらも、メモリを固定長の「単語」または「セル」の線形配列と見なす「型のない」言語でした。 . これらの古い言語では、次のような配列を宣言すると

auto V[10]; 

11個のメモリセルが確保されました。という名前のオブジェクト用に 1 つV、配列要素用にさらに 10 個。配列の最初の要素のアドレスが に格納されましたV

Dennis Ritchie の論文The Development of the C Language から:

型表記を拡張しようとしたとき、特に構造化 (レコード) 型を追加しようとしたときに、問題が明らかになりました。構造体は直感的な方法でマシンのメモリにマップする必要があるように見えましたが、配列を含む構造体では、配列のベースを含むポインターを格納する適切な場所も、それを配置する便利な方法もありませんでした。初期化されました。たとえば、初期の Unix システムのディレクトリ エントリは、C では次のように記述される場合があります。

構造体 {
    int inumber;
    文字名[14];
};
単に抽象的なオブジェクトを特徴付けるだけでなく、ディレクトリから読み取られる可能性のあるビットのコレクションを記述する構造も必要でした。セマンティクスが要求する名前へのポインターをコンパイラーはどこに隠すことができますか? 構造がより抽象的に考えられていて、ポインターのスペースが何らかの形で隠されていても、複雑なオブジェクトを割り当てるときに、これらのポインターを適切に初期化するという技術的な問題をどのように処理できますか?

この解決策は、型のない BCPL と型付きの C の間の進化の連鎖における重要なジャンプを構成しました。ストレージ内のポインターの実体化を排除し、代わりに配列名が式で言及されたときにポインターを作成しました。今日の C で生き残っているルールは、配列型の値が式に現れると、配列を構成する最初のオブジェクトへのポインターに変換されるというものです。

鉱山を強調します。これが、C の配列式が構造体型を含む他のすべての式型とは異なる方法で扱われる理由です。

于 2013-02-12T23:22:50.250 に答える
1

ドゥー=バー; //これは合法ですか?

いいえ、試してください:

doo = & bar;
     ^^

ドゥー.x = 0; // ドットを使用できないのはなぜですか?

dooポインタだからです。試す:

doo->x = 0;
   ^^
于 2013-02-12T21:23:58.973 に答える
1

いいえ、ちがいます。あなたがしたいことは次のとおりです。

doo = &bar; 
doo->x = 0;

配列の場合、 の配列Tは暗黙的に に変換できるため機能しますT*が、構造体の場合はそうではありません。ポインターは、struct objext ( &bar) のアドレスを格納できます。ポインターを使用して構造体要素に間接的にアクセスするには、-> 演算子を使用する必要があります。a->bと同等です(*a).b

于 2013-02-12T21:24:13.560 に答える
1
  doo = bar; //is this legal?

いいえ、無効です。左のオペランドは構造体型で、右のオペランドはポインター型です。

これは合法です:

 doo = &bar;

&barへのポインタ型struct fooです。

今:

  doo.x = 0; //why can't I use the dot?

オペランドは構造体型である必要がありますが、ポインター型であるためです。->構造体型へのポインターのオブジェクトから要素にアクセスするために使用します。

  doo->x = 0;  // this is valid
于 2013-02-12T21:24:15.907 に答える
1

いいえ、構造体の値はアドレスではなく、構造体そのものです。これにより、次のようなことができます。

struct foo a;
struct foo b;
b = a;  /* this does a memberwise copy of all fields from a to b */

構造体のアドレスが必要な場合は、次の&演算子を使用します。

struct foo a;
struct foo* b = &a
struct foo c;
c = *b;  /* this does a memberwise copy of all fields from a to c */
于 2013-02-12T21:26:27.200 に答える