我正在学习如何创建头文件并分离实现,同时也开始了解如何创建链接列表。我创建了linked_list.h
,linked_list.c
和main.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
}
答案 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
中定义typedef
和linked_list.h
,如下所示:
struct Listnode_ {
int data;
struct ListNode_ *next;
};
typedef struct Listnode_ Listnode;
您无法声明实际变量的原因是因为main.c
不知道其结构是什么,因此它无法为其分配内存。你 CAN 但是声明一个指针,因为所有指针内部都有相同的结构,无论它们是什么类型。这称为PIMPLE
概念(指向IMPLEmentation的指针),即使您不知道它是什么,您也可以声明指向某个实现的指针 - 它是C提供的一种抽象形式。