-1

I know this question is getting old, but I can't seem to understand what's wrong with my code.

I have a tree.c file with the following struct tree, and this file includes a header file in which is declared a pointer to this type of struct:

tree.c

#include "tree.h"

typedef struct tree
{
    char desig[200];
    int num;
    tree_ptr left, right, subtree;
} Tree;

tree.h

#ifndef ___TREE_H___
#define ___TREE_H___

typedef struct tree *tree_ptr;

#endif

When I try to access some instance of this struct in another source file, the compiler gives me the "dereferencing pointer to incomplete type" error:

insert(..., instance->subtree);

What's wrong?

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
PablodeAcero
  • 399
  • 8
  • 20
  • 1
    Perhaps the code calling `insert()` sees the typedef but not the actual structure? – mah Mar 20 '15 at 17:10
  • maybe better to move you type declaration to the header. – Jason Hu Mar 20 '15 at 17:11
  • When you include `tree.h` in, say, `treeUser.c`, ask yourself: has the compiler seen any mention of `subtree` in `treeUser.c`? Or is `subtree` a completely unknown concept when you compile `treeUser.c`? –  Mar 20 '15 at 17:13
  • You are saying that I should include the header after the struct declaration? – PablodeAcero Mar 20 '15 at 17:14
  • Don't use names starting with a double-underscore (or, indeed, with a single underscore). They are reserved for use by 'the implementation', and you'll know if you're implementing 'the implementation' (but, hint, if you aren't writing the C compiler and its support library, you aren't implementing 'the implementation'). – Jonathan Leffler Mar 20 '15 at 17:23
  • You need to create an MCVE ([Minimal, Complete, Verifiable Example](http://stackoverflow.com/help/mcve)) or SSCCE ([Short, Self-Contained, Correct Example](http://sscce.org/)) so we can reproduce your problem. If you are trying the access in `tree.c`, there shouldn't be a problem. If you're trying to access `instance->subtree` in some other source file and `instance` is a `tree_ptr`, then you are breaking the rules and the compiler is correct in chastising you. – Jonathan Leffler Mar 20 '15 at 17:25
  • @JonathanLeffler Yes, I'm trying to access exactly like that in another source file. I'm including the header in that source file. What can I do to correct the problem? Thank you. – PablodeAcero Mar 20 '15 at 17:38
  • See [Why can I use a typedef of a type that doesn't exist](http://stackoverflow.com/q/25432427/). Basically, you can have opaque types where you pass pointers to those types around, but you cannot dereference the pointers, or you can have complete types where the details of the structure are known. If your code needs to access the internals of the structure, then you need to include the structure definition in your header. If you don't want code outside the implementation file to access the details, provide access functions. See also [Hide type definition](http://stackoverflow.com/q/9269691/) – Jonathan Leffler Mar 20 '15 at 17:43

3 Answers3

1

Try making the following your tree.h file:

   #ifndef  tree_h_
   #define  tree_h_

   typedef struct tree
   {
       char desig[200];
       int num;
       struct tree *left, *right, *subtree;
    } Tree;

   typedef struct tree *tree_ptr;

   #endif

and removing the declaration of Tree from you implementation file. Due not showing a small,working MCVE or a SSCCE, I can't test the above solution in your specific case, however the following simplistic program compiles (gcc -ansi -pedantic -Wall tree.c -o tree_test) without warning or error :

file tree.c

    #include <stdio.h>
    #include <stdlib.h>
    #include "tree.h"


    int main(int argc, char* argv[])
    {
         Tree  root;

         root.left = malloc(sizeof(Tree));
         root.right = malloc(sizeof(Tree));
         root.subtree = NULL;

         if((NULL != root.left) && (NULL != root.right))
         {
             root.left->left = NULL;
             root.left->left = NULL;

             root.right->left = NULL;
             root.right->right = NULL;
         }

         return 0;
    }

This was tested using gcc version 4.8.2 on a Centos 7 system.

N.B. I've presented only minimalist error checking, no error handling and no clean-up code to keep the example short. Certainly in your code you should insure complete error checking, error handling and clean-up.

thurizas
  • 2,473
  • 1
  • 14
  • 15
0

Your header file has only definition for pointer type "tree_ptr". Pointers are always 4 bytes on 32 bit machines no mater what they are pointing too. So as long as you are not accessing the members of "struct tree" you are okay i.e when you assign value to pointer of type "tree_ptr" or when checking if the pointer of type "tree_ptr" is not NULL. These kind of operations don't require complete struct definition. But if you want to access the members of this struct your code needs the struct definition in the scope. Structs are not like functions so you cant declare them them in the header and define in the .c file. So I suggest you move your struct definition to your header file.

binW
  • 13,220
  • 11
  • 56
  • 69
0

The other source files cannot see your tree.c and have absolutely no knowledge of what's inside your tree.c. All they can see is tree.h which declares

typedef struct tree *tree_ptr;

And that declares struct tree as an incomplete type.

Your struct tree is a complete type inside tree.c and only inside tree.c. In all other .c files it is an incomplete type. If you want it to be complete in all source files that include tree.h, you will have to move the full declaration of struct tree to tree.h.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765