5
#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 the commented line, it generates a dereferencing incomplete type error. Can anyone explain the reason?

Sharon
  • 171
  • 1
  • 13
  • 2
    I was able to compile and run your code with no warning and errors simply changing `typedef struct data` to `typedef struct node`. – Vicente Cunha Feb 24 '16 at 16:18
  • Basic stuff: you cannot use the `typedef` name inside the struct you're `typedef`'ing. the type is also `node`, not `struct node`. Because you used `struct node`, you're implying there is a `struct node` declared somewhere. – Elias Van Ootegem Feb 24 '16 at 16:27
  • This code works. But if I include that commented printf statement, it generates error – Sharon Feb 24 '16 at 16:29
  • try my modifications below, it should work fine. – ReshaD Feb 24 '16 at 16:33
  • That does not make any difference. Please explain me the reason why the code works correctly without that commented line – Sharon Feb 24 '16 at 16:45
  • @elantra Now I will write the whole code, which does not give any error on my compiler and prints out 8 10 8. – ReshaD Feb 24 '16 at 16:49

4 Answers4

2

First of all you should modify your struct, and the error of the commented part should be solved:

typedef struct data
{

   int num;
   struct data *link;

}node;

When you are defining s and new in the following lines, there is no need to put them equal to NULL, This is the working fine 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;
}
ReshaD
  • 936
  • 2
  • 18
  • 30
2

This is a naming confusion.

node == struct data thanks to typedef.

But node != struct node. They are 2 distinct types. And struct node has not been defined.

This is a pity that such a confusing construction is allowed by the C standard, and not even flagged as a warning by compilers. But that's the way C is defined today, so we have to live with it.

My recommendation : don't 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 will avoid naming confusions such as this one.

The solution is now pretty obvious. Replace :

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

by

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

and the problematic printf will now work.

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

Now that's an interesting one.

Let's go back to the initial definition. As we said, struct node doesn't exist, and is therefore incomplete. Just to better follow what we are going to explain, let's call it struct incomplete_s instead. Now, node becomes :

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

It will still work without the problematic printf.

The reason is, node is properly defined. It is a structure with known size and types. Because it doesn't matter that struct incomplete_s is incomplete, since link is defined as a pointer to it. You could as well have defined void * link; and it would still work.

void* or struct incomplete_s * or whatever * have all same size : they are all pointers. So the structure hosting them can be properly created.

In your main loop, your program does :

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

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

Note that both pointers are supposed to point to different types. But they are both pointers, so yeah, this assignment is technically possible and authorized by the standard.

Now a more cautious compiler would likely issue a warning here, since you are not supposed to mix pointers of different types. This is a silent type-casting, which is a recipe for future bugs. I don't know which compiler you use, but you could increase its warning level (use "warning level 4" for Visual, or -Wall -Wextra for gcc), and it will likely not like this = operation.

A more explicit type casting would solve that (*) : e = (node*)(e->link);

Now this is no more silent, programmer is in charge, warnings will disappear.

e->link definitely exists, so compiler can grab this value. But s->link->num doesn't 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 complement : At some higher optimization level, this will still be not good : strict aliasing might get in the way. So dereferencing a pointer type into another pointer type remains a dangerous operation.

Community
  • 1
  • 1
Cyan
  • 13,248
  • 8
  • 43
  • 78
0

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

I guess struct node *link; in the declaration of struct should be struct data *link;.

MikeCAT
  • 73,922
  • 11
  • 45
  • 70
  • what about this; `s->link=new; new->num=8; new->link=NULL;` – Samer Feb 24 '16 at 16:10
  • But I am getting the output if the printf("%d\n",s->link->num); is commented.Can you please help me with the reason? s->link->num creates the problem. – Sharon Feb 24 '16 at 16:25
0

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

The reasons you are getting the error on the commented line is because it's the unique line you used a member of the link member in the node structure. On any other part of your code you don't hit it as you do, for example, e = new->link; the compiler don't need to 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 ok.

That's also the reason when you change the typedef struct data { …}; to typedef struct node { …}; and everything works, because when the compiler needs the information about the structure node it finds a structure called node and there is a member called link that have a member called num. As you can see, typedef is just a kind of aliasing. Hope it helps you to understand.

Jean Jung
  • 1,200
  • 12
  • 29