我是C编程的新手,有以下代码。我面临以下错误。
typedef struct Vertex Vertex;
typedef struct Edge Edge;
struct Vertex {
bool known;
char id[25];
Edge edges[20];
int distance;
};
struct Edge {
Vertex target;
int weight;
};
typedef struct {
Vertex Nodes[20];
int pass;
int infinity;
} Graph;
它给出的错误是:
数组类型具有不完整的元素类型
有人可以帮我了解问题所在吗?
typedef struct Vertex Vertex;
typedef struct Edge Vertex;
这可能会产生一些名称冲突,只需更改其中一个的名称即可。
唯一可行的方法是混合使用指针并解决如何实现Vertex
和Edge
结构:
/*your typedefs didn't make sense to me as it was conflicting. So, I edited it accordingly*/
//typedef struct Vertex Vertex;
//typedef struct Edge Vertex;
struct Vertex;
struct Edge;
typedef struct Vertex {
bool known;
char id[25];
struct Edge *edges;//This HAS to be a pointer.
int distance;
} Vertex;
typedef struct Edge {
Vertex target;
int weight;
} Edge;
typedef struct {
Vertex Nodes[20];
int pass;
int infinity;
} Graph;
为什么会这样?因为有一种叫做前向声明的东西:
。前向声明是标识符的声明(表示 类型、变量或函数等实体),其 程序员还没有给出一个完整的定义。它是必需的 一个编译器,用于了解标识符的类型(内存大小 分配,类型检查的类型,例如函数的签名), 但不是它持有的特定值(在变量的情况下)或 定义(在函数的情况下)...
在此声明中
struct Vertex {
bool known;
char id[25];
Edge edges[20];
int distance;
};
尚未声明类型 Edge
。这里的编译器只知道它将对应于一个struct Edge
,但struct
本身是未知的。
有人可以帮我了解问题所在吗?
数组具有以下属性:
- 它的所有元素都具有相同的大小。
- 元素是连续存储的。
这允许计算每个元素的内存地址(例如 id[i]
)从第一个元素的大小和内存地址以及索引i
。
为此,编译器需要知道数组元素的大小。声明 Vertex::edges[20]
成员时,编译器还不知道 Edge
类型的对象有多大。因此编译器错误。
避免这种情况的一种方法是在Vertex
结构之前定义Edge
结构。在您的情况下,这无济于事,因为Edge::target
是 Vertex
类型,您将收到类似的错误。结构成员的内存地址是使用对象的内存地址计算的,并添加所请求成员之前的成员的大小(可能还有一些填充)。
在这种情况下,对于循环依赖项,可以使用指针作为成员,因为无论结构具有哪个成员,指向结构的指针都具有指针指向的相同大小。
想一想:编译器必须知道顶点和边缘结构的大小。如果使 Edge 包含顶点,而 Vertex 包含 Edge,则无法真正理清大小。解决方案是只提供指向结构的指针(编译器应该知道指针大小)。我会使用带有小改动的 jrd1 版本:
struct Edge {
struct Vertex* target;
int weight;
} Edge;
typedef struct Vertex {
bool known;
char id[25];
struct Edge edges[20];
int distance;
} Vertex;
typedef struct {
Vertex Nodes[20];
int pass;
int infinity;
} Graph;
这应该可以正常工作。
此外,如果每个边都应该将顶点指向它所在的位置,你真的不需要存储该指针,如果你愿意,你可以在 linux 内核中使用类似 container_of 宏的东西。