I am new to C and seem to have a misunderstanding of how header files seem to work.
For simplicities sake, I have three files: tree.h, lib.c, and main.c
In tree.h, I have
struct Node
{
void* item;
Node** nodes;
};
struct Tree
{
Node* tree_root;
int depth, item_size;
};
void initializeTree(Tree*, int);
It is my understanding that this initializeTree method is a function "signature', and that the compiler then will know a little about the function whenever I call it in lib.c, or any other .c file that includes the header file tree.h.
However, in lib.c I have the error 'identifier Tree is undefined'.
#include <tree.h>
void initializeTree(Tree* tree, int item_size)
What is causing this error? Would the compiler not be able to 'see' the Tree struct from the included header file?
There is no Tree, there is only a struct Tree(a). While C++ allows the short form, C does not.
In C++, a struct is a slight variation on a class and they are both types accessible without the struct/class prefix. However, the rules in C are different because, despite the similarities and history of the two languages, they are now very different beasts.
So, in C, you either have to use the full type name:
struct Tree { blah blah };
void initializeTree(struct Tree *, int);
or typedef it thus:
typedef struct sTree { blah blah } Tree; // struct sTree =~ Tree
void initializeTree(Tree *, int);
(a) You have the same issue with Node, by the way.
Related
I have two header files:
src/util/buffer.h:
//Namespace Src Util Buffer sub
struct sub_buffer{
size_t size;
void *buf;
};
//tons of static inline functions
src/lib_context.h:
//Namespace Src Lib Context slc
typedef struct sub_buffer slc_buffer; // Is this typedef ok?
struct slc_context{
//definition
};
void slc_set_buffer(slc_buffer *buf_ptr);
//tons of other structs and functions
The thing that I was not sure about was the typedef struct sub_buffer slc_buffer;. There was a choice to include the src/util/buffer.h, but that would intoroduce tightly coupling to the header and it would be more difficult to replace it with e.g. another buffer definition containing flexible array member.
Is it common to introduce such a typedef to the structure that is defined in another header file so its implementation will be provided in the c file when including the header (but not to include one header to another header file)?
No, that would be an error.
You probably meant
typedef struct sub_buffer slc_buffer;
in which case it's fine, you can always introduce typedef aliases to types, even without having those types defined in the scope you're in.
This is the reason the classical self-referencing "node" works:
typedef struct node node;
struct node {
node *next;
void *data;
};
Notice how on the first line a typedef for an unknown type is used.
I decided to make static library realising doubly linked lists with functions. Its header file is like this now:
#ifndef LISTS
#define LISTS
#define LIST {0, NULL, NULL}
typedef struct node node;
typedef struct list {
unsigned int length;
node *beginning;
node *end;
} list;
void listAppend(list *list, int value);
int listPop(list *list);
char listRemove(list *list, int value);
void listPrint(list *list);
void listClear(list *list);
#endif
i.e. user should initialize list with list myList = LIST;.
Can I prevent list.length from casual changing by user in his code like list.length++?
Usually, if you want to hide implementation from client in pure C, you might use pointers to incomplete types. To do this, you put forward declaration of your struct in .h file and its full declaration in *.c file. You can't even add literal zero to a pointer to incomplete type, not to mention dereference it and/or alter some data.
Also, if you want to go against all odds and put your lists's header on stack, you might want to write a macro around alloca(), however I'm not sure how to calculate size of your struct in *.h file without having its declaration in scope. it's possible via extern const, but IMHO it's too complicated.
I have to create a program that performs various functions with a linked list. I must save the functions in a separate file from the main() but then I can't figure out how to include the list in the header file.
I tried different combinations and right now I have this in the linkedList.h file:
typedef struct list_elements* item;
And this in the linkedList.c
typedef struct list_elements{
int value;
struct list_elements *next;
}item
The problem is that when I try to compile the main.c I get the message: "request for member ‘value’ in something not a structure or union" and "request for member ‘next’ in something not a structure or union".
I looked on the suggested textbooks and online but I cannot find an explanation on how to use linked lists with header files?
(The functions work when I tested the whole thing in a single file, so I don't think they are the problem);
You are trying to typedef the same identifier twice as different types.
Remove the first typedef typedef struct list_elements* item; and put the second one in the header linkedList.h, which must be included in linkedList.c.
The declaration from your header defines type item as a pointer to a struct list_elements. The declaration from linkedList.c declares the same name, item, as an alias for type struct list_elements itself. Although this is not inherently wrong, it is certain to be confusing. It does make it wrong for linkedList.c to #include the header file, which ordinarily it would be appropriate for it to do.
You should make all your type declarations in the header file, and include it in both C source files to ensure that they share those declarations. Type declarations include at least typedefs, struct and union declarations, and function prototypes. This is not an exclusive list of things you might want to put in a header.
There is more than one way to do that:
one of them is to define the structures with the functions' prototype you want to use in a .h file, and the code of the functions in a separate .c (with the same prototypes written in the .h file of course), then you are now ready to use the structure in any other .c file by including your header file. e.g:
StType.h
typedef struct Something{
int a;
int b;
}
typedef struct anotherSomething{
int c;
int d;
}
int fct1();
int fct2();
Fct.c
include StType.h;
int fct1()
{
//...
}
void fct2()
{
//...
}
your program.c
include StType.h
int main()
{
Something s;
fct1();
}
I usualy does something like this.
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?
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.
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.
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.
typedef struct node{
int term;
struct node *next;
}node;
typedef void(*PTR )(void *);
typedef void(*PTR1)(void *,int,int);
typedef int(*PTR2)(void *,int);
typedef void(*PTR3)(void *,int);
typedef void(*PTR4)(void *,void *,void *);
typedef struct list{
node *front,*rear;
PTR3 INSERT;
PTR *MANY;
PTR DISPLAY,SORT,READ;
PTR4 MERGE;
}list;
void constructor(list **S)
{
(*S)=calloc(1,sizeof(list));
(*S)->front=(*S)->rear=NULL;
(*S)->INSERT=push_with_value;
(*S)->READ=read;
(*S)->SORT=sort;
(*S)->DISPLAY=display;
(*S)->MERGE=merger;
(*S)->MANY=calloc(2,sizeof(PTR));
(*S)->MANY[1]=read;
}
int main()
{
list *S1,*S2,*S3;
constructor(&S1);
constructor(&S2);
constructor(&S3);
S1->MANY[1](S1);
S1->SORT(S1);
S1->DISPLAY(S1);
return 0;
}
The void * parameter in all such functions gets typecast to list * inside the function.
Is there any way through which I can call S1->READIT; by changing the MANY[1] to another name like READ_IT;?
I intend to create a common header file, so that I can use it for all my programs.
Since I don't know how many function pointers I will need I intend to create a dynamic array of each function pointer type.
typedef struct list{
node *front,*rear;
PTR3 INSERT;
PTR READIT;
PTR DISPLAY,SORT,READ;
PTR4 MERGE;
}list;
...
(*S)->READIT = read;
...
S1->READIT(S1);
Take a look at the Linux kernel implementation of (doubly linked) lists, as defined here (and following/referenced files). They are used all over the place. Most of the manipulation is done in macros to e.g. run an operation on all nodes of the list.
If what you are trying to define is getting too complicated, step back and look for simpler alternatives. Don't generalize beforehand; if the generalization isn't used it is a waste; if something (slightly) different is later needed, it is a poor match that requires workarounds or even reimplementation.
Take a look at the interfaces exposed by the C++ STL list, those folks have thought long and hard on the matter (in a different setting, though).
Or just bite the bullet and use C++ if you want full-fledged OOP.