1

对于以下图表声明(我无法更改 - 分配),

#define TAG(vp)   ((vp)->tag)
#define LABEL(vp) ((vp)->label)  
#define EDGE(vp)  ((vp)->edge)

typedef struct vertex 
{
    char tag;
    char *label;
    struct vertex *edge[1];
}
vertex, *vp;       

当我使用以下行分配内存时

EDGE (test) = (vp *) malloc (sizeof (vp) * 3); // where test is a node of a graph

我收到以下错误

error: incompatible types when assigning to type ‘struct vertex *[1]’ from type ‘struct vertex **

我也不能将 EDGE 分配为 NULL。我想我在声明中遗漏了一些东西(它使用 *ptr[1] 这让我很困惑)。你能帮我吗?

提前致谢。

4

4 回答 4

5

您正在查看的是 C99 之前的代码,称为"struct hack"。在 C99 或更高版本中,您将使用灵活的数组成员

一般的想法是,您分配结构以及最后通过数组成员使用的一些额外空间:

struct vertex *v = malloc(sizeof *v + n * sizeof(struct vertex *));

n边缘分配一个带有空间的结构(和一个哨兵,正如@EricPostpischil 在下面提到的)。我没有使用你的*vptypedef,因为我不喜欢像这样通过 typedef 隐藏指针类型。

分配后,您可以像往常一样使用数组:

v->edge[0] = &someOtherVertex;
v->edge[1] = &someOtherOtherVertex;

等等。

于 2013-05-30T14:16:37.813 回答
2

如果您希望每个顶点只有一条边,请执行以下操作:

struct vertex *edge;

或者你可以修改你的宏(ug?为什么?)例如:

#define EDGE(vp)  ((vp)->edge[0])

但您可能想要第一个选项,因为您似乎正在动态创建数组。

您不能做的是分配给数组本身:将其设为指针或分配给数组的(唯一)元素。

请注意,在 C 中创建动态数组的常用习惯用法是声明一个普通指针并使其指向动态数组的第一个元素。

于 2013-05-30T14:14:46.227 回答
0

使用现成的 linux 系统程序,cdecl我可以看到什么

 struct vertex *edge[1];

意思是:

adi@laps:~$ cdecl
Type `help' or `?' for help
cdecl> explain struct vertex *edge[1];
declare edge as array 1 of pointer to struct vertex
cdecl> 

因此,您指定的数据结构将来自顶点的边表示为存储在结构中的指针。因为您不知道有多少边,所以您可以使用哨兵 NULL 来标记数组的结尾。

因此EDGE(vp)[0]是第一个重合顶点,EDGE(vp)[1]是第二个,依此类推,直到您读取 NULL。

这称为尾随数组习语,您必须记住这sizeof(struct vertex)是没有边的顶点(只有哨兵)所需的内存量,并且每当向顶点添加更多边时,您必须确保为块分配了足够的内存持有结构。

此外,这个习语在 C99 中已被标准化为灵活数组,不同之处在于您不声明数组的大小

 struct vertex {
      struct vertex* edge[];
 }
于 2013-05-30T14:18:18.010 回答
0

代替

EDGE (test) = (vp *) malloc (sizeof (vp) * 3);

你需要做

EDGE (test) = malloc (sizeof (vp)); // to allocate array of pointer to vertex
EDGE (test)[0] = malloc (sizeof (vertex)); // to allocate the vertex itself.

如果你不能改变

struct vertex *edge[1];
于 2013-05-30T14:27:18.637 回答