How are we able to create a pointer of type node inside the struct node when the struct is not fully defined.
struct node
{
int data;
node* next;
}
How are we able to create a pointer of type node inside the struct node when the struct is not fully defined.
struct node
{
int data;
node* next;
}
The short answer is because the standard says so.
The longer answer is that the size of a pointer (a pointer to data, anyway) is always the same and so the compiler knows what it is even though node
is not yet fully defined. It is therefore able to determine the layout of node
without knowing what is coming next, and that's enough to keep it happy.
Contrast your code snippet with this:
struct node
{
int data;
node next;
};
Now the compiler is in trouble, because each next
will contain another node
which will contain another next
and so on, ad-infinitum. This code, therefore, will not compile. But with a pointer, it's fine.
As per @GoswinvonBrederlow's comments, more formally struct node
introduces node
as an incomplete type, even if you immediately follow it by { ... };
, and within the declaration of node
, node
is considered declared but incomplete.
Following on from that, diving into the standard tells us that:
... Pointers to incomplete types are allowed ...
which is what makes your example work. As I say, it's how the language is designed. C is much the same.
When you ask the compiler to allocate node* next you actually ask to allocate memory of size of a pointer, which is fixed size for all pointers types.
So the compiler don't need to know the size of struct node when you declare it.
To understand this, you need to know that the computer doesn't understand high-level software conceptualizations like structs.
In fact, when compiling your code to assembly, no such thing as a structure is ever generated. Instead, from the parsing/semantic analysis of the C compiler, a clearly structured code is generated, where your CPU will fulfill its purpose through the addressing of bits in the different transistors through routing tables.
typedef struct {
int x;
} entity_t;
int main(){
entity_t entity;
entity.x = 34;
}
Assembly Code: Simply, a value assignment to a static memory location with a 4-bit weight occurs on the stack of the main function.
main:
push rbp
mov rbp, rsp
mov DWORD PTR [rbp-4], 34
mov eax, 0
pop rbp
ret
These routing tables have 2 rule classification categories to have a data transmission format through the buses, these categories are: The memory address of a static/dynamic location of the RAM/CPU Cache and the value stored in that memory address (bits).
From this, Dennis Ritchie proposed the concept of subroutines as abstraction layers to spare us all the complexity involved in managing memory from assembler pointers.
Now, concepts as complex as recursion, in the first instance would be impossible to implement in computation because the definition tells us that a recursive function must call itself even if it is not completely defined.
Faced with this problem, C handles recursion from pointers, since pointers are entities with a memory address totally different from the address of the type or function to which you want to apply recursion. For this reason, for a recursive data structure like a linked list, it is only possible to have a link to another memory location of the same type through pointers.
In short, recursion in this type of data structure is possible through pointers because the pointer itself is a completely different memory address than the containing type.
forward declarations
struct node;
struct node
{
int data;
node* next;
}