为什么我的结构必须被声明为指针?

时间:2016-07-04 00:28:07

标签: c pointers struct header typedef

我正在学习如何创建头文件并分离实现,同时也开始了解如何创建链接列表。我创建了linked_list.hlinked_list.cmain.c个文件。在main.c我在尝试创建结构时遇到错误我输入了#def,但除非我将其创建为指针,否则它会起作用。我不明白为什么会这样,有人可以解释一下吗?

linked_list.h

#ifndef LINKED_LIST_H_
#define LINKED_LIST_H_

typedef struct ListNode_ ListNode;

#endif // LINKED_LIST_H_

linked_list.c

#include <stdio.h>
#include <stdlib.h>
#include "linked_list.h"

struct ListNode_ {
    int data;
    ListNode *next;
};

main.c

#include <stdio.h>
#include <stdlib.h>
#include "linked_list.h"

int main() {

    ListNode node1; // why can't I do this?
    ListNode *node2;    // but this works
}

3 个答案:

答案 0 :(得分:2)

ListNode中声明main.c时,您需要考虑编译器的作用。它将typedef视为struct ListNode_,但在编译struct ListNode_时它并不知道main.c是什么。要解决此问题,您需要将struct ListNode_的定义移至linked_list.h

指向ListNode的指针有效,因为可以声明指向未知大小的对象的指针,例如struct ListNode_。但是,如果您希望声明一个完整的ListNode,编译器需要知道它的大小。但由于编译器单独编译每个源文件,因此它不知道struct ListNode_中的linked_list.c,因此会抛出错误。

答案 1 :(得分:2)

这是因为尽管已经声明了ListNode和ListNode_,但只定义了ListNode_。编译器不知道ListNode对象可以包含或执行的操作。

是的,您可以指向ListNode。但是,您无法使用它们。尝试输入

//ListNode node1; // why can't I do this?
ListNode *node2;    // but this works
node2->foo();

并且您将收到有关不完整类型的相同编译错误消息。只有指针存储在某个地方才可以,因为它毕竟只是一个地址而且程序只需要知道它指向的是什么。

是的,你不使用node1但它仍然会给你一个错误。为什么?因为程序将自动为node1分配空间,并且不知道该空间应该是多少。更不用说它应该自动调用它的构造函数,而这个构造函数也没有被定义。

这也是为什么在这里

struct ListNode_ {
    int data;
    ListNode *next;
};

你被允许拥有那个指针。

我忽略了文件尚未正确链接的事实,因为评论中对此进行了讨论,无论如何都与此问题无关。

答案 2 :(得分:2)

由于您已经使用了多个文件,因此您需要更加小心,确保所有文件都具有struct的相同视图。特别是,您应该考虑在头文件struct ListNode中定义typedeflinked_list.h,如下所示:

struct Listnode_ {
    int data;
    struct ListNode_ *next;
};

typedef struct Listnode_ Listnode;

您无法声明实际变量的原因是因为main.c不知道其结构是什么,因此它无法为其分配内存。你 CAN 但是声明一个指针,因为所有指针内部都有相同的结构,无论它们是什么类型。这称为PIMPLE概念(指向IMPLEmentation的指针),即使您不知道它是什么,您也可以声明指向某个实现的指针 - 它是C提供的一种抽象形式。