【问题标题】:Pointers to other structures within a structure指向结构中其他结构的指针
【发布时间】:2016-10-20 12:26:50
【问题描述】:

我的讲师提供了以下一段代码,但没有充分解释它代表什么。

typedef struct _s {
    int         value;
    struct _s   *next;
}  STACKITEM;

STACKITEM    *stack = NULL;
  1. 我了解指针和结构是什么。但是,我不知道在结构中具有指向结构的指针意味着什么。请澄清并详细说明这个概念。

  2. 我不明白为什么将结构声明为 typedef。这似乎是多余的,原因如下:

一个典型的结构状态如下。

struct struct_format_name { 
members;
} individual_struct_object_name;

因此,我们将一个对象声明为一个结构,并将这种结构的格式命名为_s。那么使用 typedef 有什么意义呢?除了 typedef 关键字之外,它与您用于声明任何结构的格式相同。

  1. 我想澄清一下指向结构化格式的结构的指针(如上所述)与指向特定结构的结构的指针之间的区别。

我怀疑指向结构化格式的结构的指针,如上所述,可以指向该格式的任何结构?但是,指向具体结构的结构的指针只能指向那个特定的结构,而不是相同格式的其他结构?

【问题讨论】:

  • 请一问一答。
  • 是的,typedef 是无用的(在大多数情况下)并且令人困惑(就像你的情况一样)我的建议:如果你不需要它:不要使用它。
  • 第一个结构是一个链表:一个对象链,其中每个对象指向下一个对象。 typedef 可能是一种方便,或者更有可能:隐藏实现。很像 FILE 是底层文件结构的 typedef。
  • Xaxxion 的回答与我的观点并不冲突。事实上,他说最终这两种形式是等价的(结果是一样的),我的意见是你只需要一种形式(并且为已经有的东西引入另一个名字不需要名称。可能会造成混淆)
  • @ThePointer:不,可以说,它并没有涵盖你所有的问题,但其中没有什么让我觉得不正确

标签: c pointers data-structures struct


【解决方案1】:

这称为链表。指针next 允许您通过让每个元素指向下一个元素并让最后一个元素具有next 指向NULL 来浏览列表,所以你知道你在最后。请参阅https://en.wikipedia.org/wiki/Linked_list您实际上并不是在存储结构,而是在存储指向下一个元素的指针,可以将其视为一个数组,但是不是对齐的元素,而是每个元素都使用其指向下一个元素地址。

至于next指针,用struct关键字声明的原因是STACKITEM类型还不存在(它是在结构体定义之后定义的)。

【讨论】:

    【解决方案2】:

    一个典型的结构声明如下。

    仅当您以后不想再创建一个时。到目前为止,您所质疑的语法是声明结构的典型方式。

    typedef 允许您使用较短的名称 struct_format_name 而不是 struct struct_format_name 来引用它。

    【讨论】:

    • 经过进一步研究,我认为您的答案不正确。我可以通过标签引用它来创建另一个相同格式的结构。在这种情况下,这将是 struct_format_name。请随时纠正我。
    • 哦,对不起。我误读了你说的话。无论如何,通常的做法是在头文件中声明结构,然后再创建它的实例 - 通常只在定义其结构的同时创建一个,而您只打算创建一个。 typedef 位只是使您免于每次都使用类型类型“struct struct_type”——您保存一个“struct”
    • 好的,这是有道理的。谢谢你。我将使用您的 cmets 以供将来参考。 :)
    【解决方案3】:

    我了解指针和结构是什么。但是,我不明白在结构中具有指向结构的指针意味着什么。请澄清并详细说明这个概念。

    这是一种称为 singly linked list 的数据结构的常见 C 实现,其中列表中的每个元素显式指向以下元素。在这种情况下,struct _s 的每个实例都指向struct _s 的另一个实例,如下所示:

    +---+---+         +---+---+        +---+---+
    |   |   | ----->  |   |   | -----> |   |   |
    +---+---+         +---+---+        +---+---+
                                         ^   ^
                                         |   |
                                         |   +---- next
                                         +-------- value
    

    您可以使用链表结构实现stack,这就是您的讲师正在做的事情。 “推送”操作将动态创建一个新的STACKITEM,将整数值保存到其中,并使新的STACKITEM 成为列表的头部(也就是堆栈的顶部)。 stack 指针始终指向列表中的第一个元素(NULL 如果列表为空)。

    stack: |||
    
    push( &stack, 1 );
    
           +---+---+
    stack: | 1 |   |---|||
           +---+---+
    

    push 的重复调用将在列表的头部添加一个新元素:

    push( &stack, 2 );
    
           +---+---+    +---+---+
    stack: | 2 |   |--->| 1 |   |---|||
           +---+---+    +---+---+
    
    push( &stack, 3 );
    
           +---+---+    +---+---+    +---+---+
    stack: | 3 |   |--->| 2 |   |--->| 1 |   |---|||
           +---+---+    +---+---+    +---+---+
    

    代码看起来像

    void push( STACKITEM **stack, int value )
    {
      STACKITEM *newItem = malloc( sizeof *newItem );
      if ( newItem )
      {
        newItem->value = value;
        newItem->next  = *stack;    // newItem now points to former top of stack
        *stack         = newItem;   // newItem is now the top of the stack
      }
    }
    

    “弹出”操作正好相反——它通过将stack 指针设置为指向下一个元素并释放该元素的内存来删除列表的第一个元素:

    void pop( STACKITEM **stack )
    {
      STACKITEM *top = *stack;
      if ( top )
      {
        *stack = top->next;
        free( top );
      }
    }
    
    pop( &stack );
    
           +---+---+    +---+---+
    stack: | 2 |   |--->| 1 |   |---|||
           +---+---+    +---+---+
    
    pop( &stack );
    
           +---+---+
    stack: | 1 |   |---|||
           +---+---+
    
    pop( &stack );
    
    stack: |||
    

    我不明白为什么将结构声明为 typedef。这似乎是多余的,原因如下:

    typedef 有两个基本用途:

    1. 简化复杂类型名称
    2. 抽象出实现细节

    在这种情况下,您的讲师的目标是 2 - 抽象出堆栈项目类型的 struct-ness。不幸的是,如果您作为该类型的 user 必须了解实现细节,那么这并没有多大用处。

    注意:您的教师不应在标签名称中使用前导下划线;带有前导下划线的标识符保留供实现使用。

    【讨论】:

      【解决方案4】:

      结构内的指针与结构外的指针没有区别,指向结构类型的指针可以指向该类型的任何对象。

      没有办法定义只能指向特定对象的类型。

      您的代码和讲师的代码完成的事情不同,因此没有冗余。
      您正在定义一个类型和一个对象;他们正在为该类型定义一个类型和不同的名称。
      (这听起来有点像您将类型与对象混淆了。)

      他们的typedef 不是绝对必要的,但这是一种非常常见的方法,可以避免在使用结构类型时输入struct

      而且您的变体非常一个典型。
      类型通常是全局定义的,而变量则尽可能在本地声明。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-10-10
        • 1970-01-01
        相关资源
        最近更新 更多