Reputation: 1320
For the following declaration of graph (that I cannot change - assignment),
#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;
when I allocate memory with the following line
EDGE (test) = (vp *) malloc (sizeof (vp) * 3); // where test is a node of a graph
I get the following error
error: incompatible types when assigning to type ‘struct vertex *[1]’ from type ‘struct vertex **
Also I cannot assign EDGE as NULL. I guess I'm missing something with the declaration (it uses *ptr[1] which is quite confusing me). Can you help?
Thanks in advance.
Upvotes: 1
Views: 125
Reputation: 3029
Instead of
EDGE (test) = (vp *) malloc (sizeof (vp) * 3);
you need to do
EDGE (test) = malloc (sizeof (vp)); // to allocate array of pointer to vertex
EDGE (test)[0] = malloc (sizeof (vertex)); // to allocate the vertex itself.
if you cannot change
struct vertex *edge[1];
Upvotes: 0
Reputation: 224844
What you're looking at is pre-C99 code called the "struct hack". In C99 or later, you'd use a flexible array member.
The general idea is that you allocate the structure plus some extra space at the end that you use through the array member:
struct vertex *v = malloc(sizeof *v + n * sizeof(struct vertex *));
To allocate a structure with space for n
edges (and a sentinel, as @EricPostpischil mentions below). I didn't use your *vp
typedef, since I don't like hiding pointer types via typedef like that.
After that allocation, you can just use the array like normal:
v->edge[0] = &someOtherVertex;
v->edge[1] = &someOtherOtherVertex;
And so on.
Upvotes: 5
Reputation: 7343
Using the readily available on linux systems program, cdecl
I can see what does
struct vertex *edge[1];
mean:
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>
Thus your prescribed data structure represents the edges coming out of a vertex as pointers stored in a structure. Because you do not have any count of how many edges there are, you are left to use a sentinel, NULL, to mark the end of the array.
Thus EDGE(vp)[0]
is the first coincident vertex, EDGE(vp)[1]
is the second, etc., until you read a NULL.
This is called the trailing array idiom and you must remember that sizeof(struct vertex)
is the amount of memory needed for a vertex having no edges (only the sentinel) and whenever adding more edges to a vertex, you must make sure that enough memory was allocated for the block holding the struct.
Also, this idiom has been standarized in C99 as the flexible arrays and the difference is you do not declare the size of the array
struct vertex {
struct vertex* edge[];
}
Upvotes: 0
Reputation: 98338
If you want just one edge per vertex do:
struct vertex *edge;
Or else you can modify your macros (ug? why?) such as:
#define EDGE(vp) ((vp)->edge[0])
but you probably want the first option, as you seem to be creating the array dynamically.
What you cannot do is to assign to the array itself: either make it a pointer or assign to the (only) element of the array.
Note that the usual idiom in C to create a dynamic array is declaring a plain pointer and make it point to the first element of the dynamic array.
Upvotes: 2