array of forward declared struct in another struct - c

I am trying to forward declare a struct A and define a struct B that contains an array of A.
I am getting error stating 'incomplete type not allowed'
This is what I have:
struct A;
struct B
{
// something
struct A x[10]; // This where I get the error incomplete type not allowed
};
struct A
{
// something
};
What am I doing wrong ?

As a work around you can declare a pointer to struct A as this
struct B
{
// something
struct A * x;
};
This is because if you have a line like
struct B b;
the b will have a member x[10]. If you did not fully declare struct A, struct B doesn't know how to allocate 10 struct A elements. In the workaround, if you only declare a pointer, struct B doesn't need to know how to allocate struct A but only need to know how to allocate one pointer.

An "incomplete type" (MSDN) is a type whose details the compiler doesn't know at a given point in the translation unit. In the declaration of members of struct B, the compiler doesn't know the size of the type (sizeof (struct A)) and therefore doesn't know how much space to leave for it. Another reason for not allowing struct members of incomplete type is that if they could, this would have allowed "circular composition" where struct A contains members of type struct B and vice versa. I don't see how the size of the result of such a circular composition could even be defined.
Workarounds:
To include struct A by value in struct B, complete the type first. Move the declaration of members of struct A above that of struct B.
A struct is allowed to include pointers to incomplete types as members. In struct B, include an array of pointers (struct A *x[10];) Then populate it with objects of type struct A allocated separately, possibly through some factory that calls malloc(sizeof(struct A)), fills out its members, and returns the pointer. You're then responsible for freeing the memory used by these instances.

Related

Why a structure is allowed to have "pointer to its own type" as member but not "(an array of the) structure type" itself?

when i try to declare the following function
typedef struct TRIE_NODE
{
char* word;
struct TRIE_NODE node[26];
}TRIE_NODE;
I get the following error:
definition of 'struct TRIE_NODE' is not complete until the closing '}'
However, if i declare this function with a pointer to the 26 nodes, it compiles just fine.
typedef struct TRIE_NODE
{
char* word;
struct TRIE_NODE* node[26];
}TRIE_NODE;
I imagine that, since this is not an instance, it's impossible for me to get a pointer to the first of those 26 arrays, but if that is the problem, how is TRIE_NODE* node[26] not also a problem? Isn't this declaration equivalent to TRIE_NODE node[1][26]?
when i try to declare the following function
Wait!! that's not a function, that's typedef-ing a structure, a user-defined type.
That said, in the first case,
typedef struct TRIE_NODE
{
char* word;
struct TRIE_NODE node[26]; //array of type struct TRIE_NODE
}TRIE_NODE;
if this has to be possible, compiler needs to know the size of the struct TRIE_NODE before it has been defined, which is impossible. So it is invalid.
On th other hand,
typedef struct TRIE_NODE
{
char* word;
struct TRIE_NODE* node[26]; //array of pointers (of type struct TRIE_NODE)
}TRIE_NODE;
is fine, as you're allocating (array of) pointers to the structure, the actual size of the structure is not required to be known by compiler at that point. So, the compiler happily allocates the pointers and the definition (construct) is perfectly valid.
To answer your own question, ask: how many bytes will
struct TRIE_NODE node[26];
occupy? In fact, what would you expect sizeof(struct TRIE_NODE) to be?
The reason
struct TRIE_NODE *node[26];
works is that we know the value of sizeof(struct TRIE_NODE*). Because all struct pointers have the same size, we can allocate an array of N struct pointers, no matter their type, even if incompletely defined.
aren't pointers and arrays almost interchangeable?
The syntax for pointers and arrays is similar. You can subscript a pointer, and you can add to an array's address. But they define different things. Basically: an array holds data, and a pointer holds an address.
In certain parts of the C standard library, you'll find structures defined like this:
struct S {
int len;
char data[1];
};
You might be tempted to ask why not use a pointer?
struct Z {
int len;
char *data;
};
Answer: struct S is actually bigger than the 5 or so bytes it seems to occupy, and the data portion begins immediately after len. In the putative struct Z example, data doesn't begin the data; the data would be somewhere else, wherever data points.
Assuming the structures are appropriate initialized, in both cases data[0] will address the first byte of the array. They're syntactically similar. But the memory layout is different. In the S case, that byte will be pretty close to (char*)&len + sizeof(len). In the Z case it will be wherever data points.
Nobody mention this, but if struct was allowed to have member or array of itself (not a pointer, but regular member or array), then the struct would be recursive and with infinite size, because the member will have one more member inside of same type and so on until infinity.

Why are typedef names used twice in struct declaration in C?

While researching queues in C, I came across an example similar to the below. Why is the struct named both at the beginning of the curly braces and after? Why is struct type used again inside of the struct when adding an item of the same type? Are these things redundant or is there a point?
typedef void* vpoint_t;
typedef struct queue_item_t{
vpoint_t void_item;
struct queue_item_t* next;
} queue_item_t;
typedef struct queue_item_t { // 1
vpoint_t void_item;
struct queue_item_t* next; // 2
} queue_item_t; // 3
First of all, note that this entire statement is defining a typedef.
3) Is saying that the new type we are in the process of defining (via typedef) is going to be named queue_item_t.
1) The name of the structure (which is being given a new name, as we go), is named struct queue_item_t. That's it's full name, including struct at the front.
2) Because the new type doesn't yet exist (remember, we're still in the process of defining it), we have to use the only name it has thus far, which is struct queue_item_t, from 1).
Note that you can have anonymous struct definitions, which allow you to omit the name from 1). A simple example:
typedef struct {
int x, y, z;
} vector3;
In your example however, since we need the structure to be able to refer to itself, the next pointer must have a type that's already defined. We can do that by forward declaring the struct, typedefing it, then defining the struct using the typedefd type for next:
struct _queue_item; // 4
typedef struct _queue_item queue_item_t; // 5
struct _queue_item { // 6
vpoint_t void_item;
queue_item_t* next; // 7
}
4) Declare that struct _queue_item exists, but don't yet provide a definition for it.
5) Typedef queue_item_t to be the same as struct _queue_item.
6) Give the definition of the structure now...
7) ...using our typedef'd queue_item_t.
All that being said... In my opinion, please don't use typedefs for structs.
struct queue_item {
void *data;
struct queue_item *next;
}
is simple and complete. You can manage to type those six extra characters.
From the Linux Kernel coding style:
Chapter 5: Typedefs
Please don't use things like "vps_t".
It's a mistake to use typedef for structures and pointers. When you see a
vps_t a;
in the source, what does it mean?
In contrast, if it says
struct virtual_container *a;
you can actually tell what "a" is.
There are exceptions, which you can read about.
Some recent related questions:
Why use an opaque “handle” that requires casting in a public API rather than a typesafe struct pointer?
Does casting a pointer back and forth from size_t or uintptr_t break strict aliasing?
Let's change the declaration a little bit to make the discussion easier to follow:
typedef struct queue_item {
vpoint_t void_item;
struct queue_item* next;
} QueueItemType;
C supports several different name spaces; one name space is reserved for tag names on unions, structures, and enumeration types. In this case, the tag name is queue_item. Another name space is reserved for regular identifers, including typedef names like QueueItemType.
The next member is being used to point to another instance of type struct queue_item (i.e., the next item in the queue). It's declared as a pointer to struct queue_item for two reasons:
A struct type cannot contain an instance of itself; for one thing, the type would have to be infinitely large (struct queue_item contains a member next, which is a struct queue_item that contains a member next, which is a struct queue_item that contains a member next, ad infinitum);
The struct type definition isn't complete until the closing }, and you can't declare an instance of an incomplete type. However, you can declare a pointer to an incomplete type, which we do below:
struct queue_item *next;
Why not use QueueItemType *next; instead of struct queue_item *next? Again, the struct type definition isn't complete at the point next is being declared; the typedef name QueueItemType doesn't exist yet. However, the tag name queue_item is already visible to the compiler, so we can declare pointers using the type struct queue_item.
Since tag names and typedef names occupy different name spaces, it's possible to use the same name for both the tag name and the typedef name without a collision. The compiler disambiguates between the two by the presence of the struct keyword.
First, I suggest to NEVER use a struct name and identical type name. Use typedef struct QUEUE_ITEM {...} queue_item_t;
As to the question: if you want to make a "recursive data structure", that is, a data structure that has pointers to instances of itself, then you must be able to tell the compiler "This field is a pointer to one of ourselves. You don't know what we look like yet completely, because I am still defineing it, so just reserve space for a pointer". To do that you declare
struct T {
...
struct T *ptr;
....
};
With the final } queue_item_t; you create a new name for the structure.
"struct foo {...} " is one thing. It defines a struct, you need to type "struct foo" in every place you use it.
"typedef ... foo" defines a new type, so you just type "foo" where you use it.
"typedef struct foo {...} foo" is an idiom so you can use both, most probably just "foo" to save keystrokes and visual pollution.

Structure declaration in c with identifer

I am try to understand this C code:
typedef struct _IntElem *IntList;
typedef struct _IntElem { int head; IntList tail;} IntElem;
I understand that it defines a recursive type, a list. However I don't understand the way it is declared. What I understand is the second line, we define a structure named IntElem which consists of an integer and an IntList. But what is the _IntElem in this declaration?
The first line allocates memory for the list?
The first line
typedef struct _IntElem *IntList;
is to just create a typedef or an alias for struct _IntElem *. The alias is named IntList. FWIW, at this point of time, the definition of struct _IntElem need not to be known to the compiler.
The second line
typedef struct _IntElem { int head; IntList tail;} IntElem;
Actually defines an user-defined type _IntElem, with two members, head as int and tail as IntList(typedefed earlier)
typedef the type to IntElem.
Please Note: There is actually no variable created, for either of the type (s) (I'm not talking about the member variables, of course, they are part of the definition). So, there is no memory allocated , as such.
So, to be explicit
But what is the _IntElem in this declaration?
the _IntElem is the name of the user-defined data type. However, in some cases, it is optional. for example,
typedef struct { char name [32]; int age; float salary;} employee;
is both perfectly fine and legal, except the fact, in this case, we're creating an alias employee to an unnamed data type.
In C, if we have:
struct X
{
stuff....
};
then X is called a struct tag. It means that struct X is the name of a type. X on its own is not the name of a type. In fact X on its own behaves like any other undeclared identifier; this struct definition only defines the specific usage struct X.
We might say that struct tags live in a different namespace to other identifiers (not to be confused with C++ namespaces!)
Sometimes people don't like typing struct X everywhere. So they use typedef (which, confusingly, means to create a type alias) in order to make a single identifier that names the type:
typedef struct X SX;
means that SX is a type. But since struct tags are in their own namespace, you could even write:
typedef struct X X;
which means that X on its own refers to the same type as struct X does.
Hopefully you understand the code you are looking at now. I think it would have been clearer to write:
struct IntElem
{
int head;
struct IntElem *tail;
};
with the optional addition to save typing:
typedef struct IntElem IntElem;
Pointer typedefs are evil, so IntList can be omitted entirely. Possibly you could keep it around to use as an opaque type for the users of your list, but you should avoid using it during your list implementation.

Why does "struct T* next" compile when T isn't an existing type?

I am using MinGW on Windows. I am building linked list and I am confused with this.
#include <stdio.h>
#include <stdlib.h>
typedef struct Data
{
int x;
int y;
struct BlaBla * next; /*compiles with no problem*/
}List;
int main(void)
{
List item;
List * head;
head = NULL;
return 0;
}
I now that struct can't have struct variable(object, instance of that struct), but can have pointer of that struct type. Didn't know that pointer can be pointer of unexisting type. struct BlaBla * next;(not for linked list, it must be struct Data * next but mean general talking)
Yes, you can, because then the compiler, upon encountering the unknown type name for the first time, assumes that there's somehwere a struct type definition with this name. Then it will forward-declare the struct name for you, let you use it as a pointer, but you can't dereference it nor can you do pointer arithmetic on it (since it's an incomplete type).
The compiler will accept code such as your example:
typedef struct Data
{
int x;
int y;
struct BlaBla * next; /*compiles with no problem*/
}List;
This is okay because the size of pointers is known to the compiler, and the compiler is assuming that the struct will be defined before it is dereferenced.
Because the compiler acts this way, it's possible to do this:
typedef struct Data
{
int x;
int y;
struct Data * next; /* points to itself */
} List;
However, if you were to include the struct inline, like this:
typedef struct Data
{
int x;
int y;
struct BlaBla blaStruct; /* Not a pointer. Won't compile. */
}List;
The compiler can't work out how big struct Data is because it doesn't know how big struct BlaBla is. To get this to compile, you need to include the definition of struct BlaBla.
Note that, as soon as you need to access the members of struct BlaBla, you will need to include the header file that defines it.
It depends on what you mean by "unexisting". If you haven't even declared BlaBla, you'll get an error.
If you've declared it but not yet defined it, that will work fine. You're allowed to have pointers to incomplete types.
In fact, that's the normal way of doing opaque pointers in C.
So, you might think that this is invalid because there's no declaration of struct BlaBla in scope:
typedef struct Data {
struct BlaBla *next; // What the ??
} List;
However, it's actually okay since it's both declaring struct BlaBla and defining next at the same time.
Of course, since definition implies declaration, this is also okay:
struct BlaBla { int xyzzy; };
typedef struct Data {
struct BlaBla *next; // What the ??
} List;
In order to declare a variable or field of a given type, pass one as a parameter, or copy one to another of the same type, the compiler has to know how many bytes the variable or field occupies, what alignment requirements it has (if any), and what other pointer types it's compatible with, but that's all the compiler needs to know about it. In all common dialects of C, a pointer to any structure will always be the same size and require the same alignment, regardless of the size of the structure to which it points or what that structure may contain, and pointers to any structure type are only compatible with other pointers to the same structure type.
Consequently, code which doesn't need to do anything with pointers to a structure except allocate space to hold the pointers themselves [as opposed to the structures at which they point], pass them as parameters, or copy them to other pointers, doesn't need to know anything about the structure type to which they point beyond its unique name. Code which needs to allocate space for a structure (as opposed to a pointer to one) or access any of its members must know more about its type, but code which doesn't do those things doesn't need such information.

copying a struct with a struct member to another struct

is the following code correct?
typedef struct
{
int x;
int y;
} OTHERSTRUCT;
struct DATATYPE
{
char a;
OTHERSTRUCT b;
}
// ...
// now we reserve two structs
struct DATATYPE structA;
struct DATATYPE structB;
// ... probably fill insome values
// now we copy structA to structB
structA = structB;
Are both structs now completely identical? Even the "struct in the struct"?
Thanks!
Yes.
When you assign one struct variable to another, every member is copied one-by-one, including the other struct OTHERSTRUCT you have as a member of DATATYPE.
Yes, their contents is the same afterwards.
There may well be padding bytes between a and b in struct DATATYPE, and these are not guaranteed to be copied by the struct assignment. That doesn't mean that they won't be, just that you can't rely on whether they are or not.
The actual members a and b will have identical values. The effect of the copy applies recursively to members of struct type, so yes the members-of-members are copied too.

Resources