【问题标题】:C99 pointer to a struct which contains a pointer to a structC99 指向结构的指针,其中包含指向结构的指针
【发布时间】:2013-03-12 22:08:44
【问题描述】:

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

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

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

太好了,我可以看到我们有我所说的嵌套结构,因为 struct 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 也很好。我什至得到我的嵌套 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,我发现书中的示例没有 有一个指向 struct rect 中的结构的指针。

我已经通过反复试验来获得我想要的东西,但这令人抓狂。 我可以创建一个“struct timespec temp”类型的临时变量,然后 set 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
}

效果很好。显然,我需要咖啡。 :-)

【问题讨论】:

  • 对不起,我有点失态。我通常使用 calloc 而不是 malloc。
  • 考虑到您开始动态分配节点结构,不只是使用struct timespec tv; 成员而不是指针并且必须调用 YAMI(还有另一个-malloc-调用)?还是你在偷偷测试堆收集器的分片合并算法?
  • 好吧,正如你所知道的,我在写这个问题时非常小心,我只是惊讶于解决方案是多么微不足道。我想我应该将 malloc 修改为 calloc,因为我更经常使用它。这让我真的怀疑自己.. 非常感谢你用 node_head->tv->tv_sec 给了我一个小小的打击。
  • 致 WhozCraig :事实上,我在结构中还有一堆其他成员,但为了简单起见,我将它们删除了。您是完全正确的,我应该将 timespec 结构保留为一个好的 ol 简单变量。但是......现在我已经完成了......我需要一个函数来添加列表中的下一个节点,并插入数据等等等。所以..列表中可能有数千个并且内存管理器工作..没问题在那里。

标签: c pointers struct


【解决方案1】:

这还不够吗?

node_head->tv->tv_sec

【讨论】:

    【解决方案2】:

    其他答案都有,但如果不清楚,-> 与自己对* 进行“取消引用”相同。

    所以

     rp->pt1
     (*rp).pt1
    

    是等价的。

    这意味着你有一个经验法则“在处理指针时使用->”。

    如果你有,

    node_head->tv->tv_sec
    

    会做你想做的,相当于

    (*node_head).tv->tv_sec
    (*(*node_head).tv).tv_sec
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

        最初的评论:您的tv 的(struct timespec *) 转换不是必需的,因为这已经是tv 的声明方式。

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

        你问过,

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

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

        【讨论】:

          【解决方案5】:

          从您的开场示例中,如果您有:

          struct rect {
              struct point *pt1;
              struct point *pt2;
          };
          
          struct point {
              int x;
              int y;
          };
          

          你有

          struct rect *rp;
          

          然后访问x你只需使用:

          rp->pt1->x
          

          编译器可以弄清楚发生了什么。如果你有 void 指针等,你只需要强制转换。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-08-28
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-03-21
            相关资源
            最近更新 更多