【问题标题】:How a pointer to structure can be used before the structure is defined?在定义结构之前如何使用指向结构的指针?
【发布时间】:2016-08-01 21:23:45
【问题描述】:

我很难理解这段代码是如何工作的。在使用指向结构的指针之前,我一直认为应该定义它。在下面的示例中,为什么编译器不抱怨 struct LL* Next ?

typedef struct LL
{
    int value;
    **struct LL* Next;**
}Node;

Node* temp;

【问题讨论】:

  • 不太确定你想问什么。你是在问为什么struct LL* Next; 不是错误?
  • 您展示的代码没有使用任何未初始化的指针。

标签: c++ c memory memory-management struct


【解决方案1】:

您可以在结构定义中使用不完整的类型(缺乏足够的信息来确定该类型对象的大小)。当你在struct LL的定义中写struct LL* Next;时,LL已经被声明为一个结构体,所以不会抛出任何错误。

其实N1570已经提供了一些例子:

10 示例 1 此机制允许声明自引用 结构。

      struct tnode {
            int count;
            struct tnode *left, *right;
      };

指定一个结构,该结构包含一个整数和两个指向 相同类型的对象。 ......

11 以下替代公式使用 typedef 机制:

      typedef struct tnode TNODE;
      struct tnode {
            int count;
            TNODE *left, *right;
      };
      TNODE s, *sp;

【讨论】:

    【解决方案2】:

    “变量应该总是被初始化”是一个经验法则。这不是一个很好的规则,有时(比如你的例子),它必须被违反,至少是暂时的。未初始化的数据(垃圾)本身不会导致问题。

    一些程序员会像这样虔诚地初始化他们的变量。

    int i = 0;
    Node * foo = NULL;
    

    没有什么能强迫你这样做。只是程序员在做不必要的事情。

    在解除引用之前初始化指向有意义的指针很重要。

    #include <stdio.h>
    #include <stdlib.h>
    
    typedef struct LL
    {
        int value;
        struct LL* next;
    }Node;
    
    int main (int argc, char ** argv)
    {
        Node * A; // OK.  A points at garbage.
        Node * B; // OK.  B points at garbage.
        B = A; // Dumb, but OK.  B now points at the same garbage as A.
        B = A->next; // ERROR.  You can't dereference garbage.
        A = malloc (sizeof(Node)); // A is no longer points at garbage.  The newly created A->value and A->Next are garbage though.
        B = A->next; // Dumb, but OK.  B now points at the same garbage as A->Next.
        B->value = 200; // ERROR.  B is garbage, you can't dereference garbage.
        A->value = 100; // OK.  A->value was garbage, but is now 100.
    
        // *********************************
    
        // Enough academic examples.  Let's finish making the linked list.
        A->next = malloc(sizeof(Node)); // OK. A->value no longer points at garbage.
        B = A->next; // OK.  B now points at the second node in the list.
        B->value = 200; // OK.  B->value was garbage, is now 200.
        B->next = NULL; // OK.  B->Next was garbage, is now NULL.
    
        printf("A: %#x, value: %d, next: %#x\n", A, A->value, A->next);
        printf("B: %#x, value: %d, next: %#x\n", B, B->value, B->next);
    
        return 0;
    }
    

    【讨论】:

    • Node * A; Node * B; B = A; 是 UB。
    • 这不是语言律师的问题。
    【解决方案3】:

    在您的代码中,

     struct LL* Next;
    

    被允许作为struct LL 定义本身的成员并且不会引发任何错误,因为此时编译器不需要知道结构本身的定义。它只需要分配一个指向结构的指针,就可以了。

    稍后,在使用struct 类型的变量时,您必须为指针分配内存并将该内存分配给指针,然后才能进一步使用。

    【讨论】:

    • 如果不使用术语不完整类型,您将无法回答这个问题。
    猜你喜欢
    • 2023-03-18
    • 2010-10-05
    • 1970-01-01
    • 1970-01-01
    • 2021-10-16
    • 2018-10-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多