An incomplete type error dereference pointer when using typedef struct in C

#include<stdio.h> typedef struct data { int num; struct node *link; }node; main() { node *s=NULL,*e=NULL,*new; new=malloc(sizeof(node)); s=malloc(sizeof(node)); s->num=10; s->link=new; new->num=8; new->link=NULL; // printf("%d\n",s->link->num); //// error: dereferencing pointer to incomplete type e=s; while(e!=NULL) { printf("%d",e->num); e=e->link; } } 

For the above C program, I got the correct output. But if I include a commented line, it generates an incomplete dereference type error. Can anyone explain the reason?

+5
source share
4 answers

This is a confusion of names.

node == struct data thanks to typedef .

But node ! = struct node . These are two different types. And the struct node not defined.

It is a pity that such an intricate construction is allowed by the C standard and is not even marked as a warning by compilers. But the way C is defined today, so we must live with it.

My recommendation: do not use the same names for struct and typedef . Create your own convention, for example struct thing_s and typedef struct thing_s thing_t; . This avoids confusing names such as this.

The solution is now pretty obvious. Replace:

typedef struct data { int num; struct node *link; } node;

typedef struct data { int num; struct data *link; } node;

and printf problem will now work.

But your question is: why does your program work at all without this printf ?

Now that is interesting.

Back to the original definition. As we already said, the struct node does not exist and, therefore, is incomplete. To better follow what we will explain, let's call it struct incomplete_s . Now node becomes:

typedef struct data { int num; struct incomplete_s *link; } node;

It will work printf no problem.

The reason is because node correctly defined. This is a structure with known sizes and types. Because it does not matter that struct incomplete_s is incomplete, since link is defined as a pointer to it. You could also define void * link; and it will still work.

void* or struct incomplete_s * or whatever * are the same size: they are all pointers. Thus, the structure of their placement can be correctly created.

In your main loop, your program:

  while(e!=NULL) { printf("%d\n",e->num); e=e->link; } 

that is, e , which is a pointer to node* , takes the value e->link , which is a pointer to struct incomplete_s * .

Please note that both pointers must point to different types. But they are both pointers, so yes, this assignment is technically possible and allowed by the standard.

Now a more careful compiler will most likely throw a warning here, since you shouldn't mix pointers of different types. This is a quiet casting type that is a recipe for future mistakes. I don’t know which compiler you are using, but you can increase its warning level (use "warning level 4" for Visual or -Wall -Wextra for gcc), and this probably will not like this operation = .

More explicit type casting will solve this (*): e = (node*)(e->link);

Now it is no more quiet, the programmer answers, the warnings disappear.

e->link definitely exists, so the compiler can capture this value. But s->link->num does not exist, since s->link is struct incomplete_s* , and we don’t know what it is, so we don’t know if it has a num member.

(*) Overkill add-on: at some higher level of optimization, it will still be inconvenient: a strict alias can interfere. Therefore, dereferencing a pointer type in another pointer type remains a dangerous operation.

+1
source

First of all, you should change your structure, and the error of the commented part should be resolved:

 typedef struct data { int num; struct data *link; }node; 

When you define s and new in the following lines, there is no need to set them to NULL, this is the main wonderful main function:

 void main(){ node *s,*e,*new; e=NULL; new=malloc(sizeof(node)); s=malloc(sizeof(node)); s->num=10; new->num=8; new->link=NULL; s->link=new; printf("%d\n",s->link->num); /// works fine without any error e=s; while(e!=NULL) { printf("%d\n",e->num); e=e->link; } return; } 
+2
source

struct node not specified in this code, so struct node* is an incomplete type.

I think struct node *link; the struct declaration must have struct data *link; .

0
source

The shortest answer: you have defined a type that needs one structure that is not declared.

The reasons you get the error in the commented line is because it is the unique line in which you used the link member in the node structure. In any other part of your code, you don’t get the way you are, for example, e = new->link; the compiler should not know about the members of the structure at this time, because you said that e is of type node, node is a structure, and new->link is a compatible structure, so everything is fine.

This is also the reason when you change typedef struct data { …}; on typedef struct node { …}; , and everything works, because when the compiler needs information about the node structure, it finds a structure called node, and there is an element called a link that has a member called num. As you can see, typedef is just aliasing. Hope this helps you understand.

0
source

Source: https://habr.com/ru/post/1243768/


All Articles