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;
}

那么这四个表达式是等价的:

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

在同一页面的早些时候,我们看到了这个:

p->member_of_structure

这被描述为“指特定成员”。

我将连字符改为下划线,以确保我们不会与减号混淆。

太好了,我可以看到我们有我所说的嵌套结构,因为结构 rect 在其中包含一个结构点。

那么 rect 的定义是什么使得 pt1 和 pt2 都是指向结构点的指针?

这是我用以下代码位遇到麻烦的地方:

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 很好。我什至得到我的嵌套结构 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

您应该更改(*node_head.tv)(*node_head).tv(或node_head->tv如 Oli 所写),因为.优先级高于*.

于 2013-03-12T22:12:15.740 回答
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

初步评论:您的(struct timespec *)演员阵容tv是不必要的,因为这已经tv是声明的方式。

正如其他人所指出的那样,您实际上只需要在ptr->field此处使用符号:node_head->tv->tv_sec. 该->符号是一种语法糖,以避免所有(*rp).(*pt1).x可能需要的笨拙。

您询问,

那么 rect 的定义是什么使得 pt1 和 pt2 都是指向结构点的指针?

在这种情况下,@teppic 的解决方案就是您想要的,但要记住的一个微妙之处是数据结构的实际内存分配在哪里:在您的示例中,实际内存分配在 中rect,在@teppic 中,它是point. 这一点对于 C 的新手来说有时很棘手,这很重要,尤其是当您在长时间运行的程序中多次分配和释放内存时(避免内存泄漏所必需的)。

于 2013-03-12T22:25:51.653 回答