3

K&R "The C Programming Language" 第 2 版では、131 ページで次のように一連の変数が指定されています。

struct rect r, *rp = &r;

どこ :

struct rect {
    struct point pt1;
    struct point pt2;
};

struct point {
    int x;
    int y;
}

これらの 4 つの式は同等です。

r.p1.x
rp->pt1.x
(r.pt1).x
(rp->pt1).x

同じページの前半で、次のように表示されます。

p->member_of_structure

これは「特定のメンバーを指す」と記述されています。

マイナス記号と混同しないように、ハイフンをアンダースコアに変更しました。

構造体rectには構造体ポイントが含まれているため、ネストされた構造体と呼ばれるものがあることがわかります。

さて、pt1 と pt2 が両方とも構造体ポイントへのポインターであったような rect の定義は何ですか?

ここで、次のコードビットで問題が発生しました。

typedef struct some_node {
    struct timespec *tv;
    struct some_node *next;
} some_node_t;

明らかに、ここでリンクされたリストを作成しますが、それは問題ありません。

本当に大きな問題はこれです:

struct timespec some_tv;
clock_gettime( CLOCK_REALTIME, &some_tv )
/* set up the head node */
struct some_node *node_head =
                ( struct some_node * ) malloc( sizeof( some_node_t ) );
node_head->tv = calloc ( (size_t) 1, sizeof ( struct timespec ) );

それはすべてうまく機能し、node_headをうまく取得できます。ネストされた struct timespec node_head->tv も問題なく取得できます。

本当の問題は、内部の tv.sec を some_tv.sec の値に次のように設定する方法を見つけようとすることです。

((struct timespec *)(*node_head.tv)).tv_sec = some_tv.tv_sec;

エラーが発生します:

line 22: error: left operand of "." must be struct/union object

だから私はK&Rを見ています.本の例には、構造体rect内の構造体へのポインタがないことがわかります。

私は試行錯誤して欲しいものを手に入れましたが、これは気が狂っています. 「struct timespec temp」タイプの一時変数を作成してから、temp = &node_head.tv を設定することはできますが、いいえ ... それは機能しません。それはもっと悪いと思います。

ここで何が欠けていますか?

もちろん、答えは簡単で、単に foo->bar->here 構文を使用するだけです。

コードを変更して malloc のキャストを削除し、正しい構文を使用します。

/* set up the node list */
struct some_node *node_head =
                calloc( (size_t) 1, sizeof( some_node_t ) );

node_head->tv = calloc ( (size_t) 1, sizeof ( struct timespec ) );
node_head->tv->tv_sec = some_tv.tv_sec;
node_head->tv->tv_nsec = some_tv.tv_nsec;
node_head->next = NULL;

デバッガーはこれを確認します:

(dbx) print *node_head
*node_head = {
    tv      = 0x1001453e0
    next    = (nil)
}

(dbx) print *node_head.tv
*node_head->tv = {
    tv_sec  = 1363127096
    tv_nsec = 996499096
}

よく働く。明らかに、コーヒーが必要です。:-)

4

5 に答える 5

5

これで十分ではありませんか?

node_head->tv->tv_sec
于 2013-03-12T22:11:55.910 に答える
2

他の回答にはそれがありますが、明確でない場合->は、自分自身で「逆参照」を行うのと同じ*です。

それで

 rp->pt1
 (*rp).pt1

同等です。

->これは、「ポインターを扱うときに使用する」という経験則があることを意味します。

あなたが持っていた場合、

node_head->tv->tv_sec

あなたが望むことを行い、同等です

(*node_head).tv->tv_sec
(*(*node_head).tv).tv_sec
于 2013-03-12T22:18:07.403 に答える
0

最初のコメント:それはすでに宣言されているので、あなたの(struct timespec *)キャストは必要ありません。tvtv

ptr->field他の人が示しているように、実際にはここで表記を使用するだけで済みますnode_head->tv->tv_sec。表記は、他の方法で必要となるすべての不器用さを回避するための->少しの構文糖衣です。(*rp).(*pt1).x

あなたは尋ねました、

さて、rectの定義は、pt1とpt2が両方とも構造体ポイントへのポインタであるようなものでしたか?

その場合、@ teppicのソリューションが必要ですが、覚えておくべき微妙な点の1つは、データ構造の実際のメモリが割り当てられている場所です。この例では、実際のメモリ割り当てはにrectあり、@teppicの場合はpointです。この点は、Cの初心者にとっては注意が必要な場合があります。特に、長時間実行されるプログラムでメモリを何度も割り当てたり解放したりする場合は重要です(メモリリークを回避するために必要です)。

于 2013-03-12T22:25:51.653 に答える
0

冒頭の例から、代わりに次の場合:

struct rect {
    struct point *pt1;
    struct point *pt2;
};

struct point {
    int x;
    int y;
};

そしてあなたは持っています

struct rect *rp;

次に、x次を使用してアクセスします。

rp->pt1->x

コンパイラは、何が起こっているかを把握できます。void ポインターなどがある場合にのみ、キャストが必要です。

于 2013-03-12T22:14:49.320 に答える
0

(*node_head.tv)に変更する必要があります(*node_head).tv(またはnode_head->tvOli が書いたように).よりも優先順位が高くなり*ます。

于 2013-03-12T22:12:15.740 に答える