Why does my struct have to be declared as a pointer? - c

I'm learning how to create header files and separate the implementation while also starting to learn about how to create a linked list. I created linked_list.h, linked_list.c, and main.c files. In main.c I get an error when trying to create the struct I typedef'ed unless I create it as a pointer, then it works. I don't understand why this is, could someone please explain this?
linked_list.h:
#ifndef LINKED_LIST_H_
#define LINKED_LIST_H_
typedef struct ListNode_ ListNode;
#endif // LINKED_LIST_H_
linked_list.c:
#include <stdio.h>
#include <stdlib.h>
#include "linked_list.h"
struct ListNode_ {
int data;
ListNode *next;
};
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "linked_list.h"
int main() {
ListNode node1; // why can't I do this?
ListNode *node2; // but this works
}

This is because despite how both ListNode and ListNode_ have been declared, only ListNode_ has been defined. The compiler doesn't know what a ListNode object can contain or do.
Yes, you can have pointers to ListNode. However, you cannot use them. Try typing
//ListNode node1; // why can't I do this?
ListNode *node2; // but this works
node2->foo();
and you'll get the same compilation error message about an incomplete type. It's ok only to have the pointer stored somewhere because it's only an address after all and the program only needs to know what it points to.
And yes, you don't use node1 but it still gives you an error. Why? Because the program will automatically have to allocate space for node1 and it has no idea how much that space should be. Not to mention it's supposed to automatically call its constructor, which, again, isn't defined.
This is also why here
struct ListNode_ {
int data;
ListNode *next;
};
you're allowed to have that pointer.
I'm ignoring the fact that the files haven't even been linked properly because that was discussed in the comments and it has nothing to do with this issue anyway.

Since you've used multiple files, you've to be a little more careful to make sure that all files have the same view of your struct. In particular, you should consider defining struct ListNode and typedefing it inside the header file linked_list.h itself, as so:
struct Listnode_ {
int data;
struct ListNode_ *next;
};
typedef struct Listnode_ Listnode;
The reason you can't declare the actual variable is because main.c doesn't know what its structure is, so it can't allocate memory for it. You CAN however declare a pointer, because all pointers have the same structure internally, no matter what type they are. This is called the PIMPLE concept (Pointer to IMPLEmentation), where you can declare pointers pointing to some implementation even if you don't know what it is - it's a form of abstraction that C offers.

You need to think about what the compiler does when you declare a ListNode in main.c. It sees the typedef to struct ListNode_, but it doesn't know what struct ListNode_ is when it is compiling main.c. To fix this, you need to move the definition of struct ListNode_ to linked_list.h.
The declaration of a pointer to ListNode works because it is possible to declare a pointer to an object of an unknown size, such as struct ListNode_ in this case. However, if you wish to declare a full-blown ListNode, the compiler needs to know what size it is. But since the compiler compiles each source file separately, it does not know about the struct ListNode_ in linked_list.c, and thus throws an error.

Related

C: Incomplete definition of type struct

this error seems very easy to fix but i've been trying and have no clue.
So i have three files:
symtable.h:
typedef struct symbolTable *SymTable_T;
symtablelist.c:
#include "symtable.h"
struct Node{
char* key;
void* value;
struct Node* next;
};
struct symbolTable{
struct Node* head;
int length;
};
SymTable_T SymTable_new(void){
/* code */
}
And main.c:
#include "symtable.h"
int main(int argc, const char * argv[]) {
// insert code here...
SymTable_T emptyTable = SymTable_new();
emptyTable->length = 3; <------- ERROR
return 0;
}
I'm getting error: Incomplete definition of type "struct symbolTable"
Can anyone please give me a hint?
The reason i declare my struct in my source file is that i will have another implementation for the header file. so is there another way to fix my bug beside moving my struct declaration?
You can't access the members directly with an opaque pointer - if you keep the implementation in a separate source file, you'll have to access all the members via your interface, and not directly mess with the struct.
For instance, add this to symtable.h:
void SymTable_set_length(SymTable_T table, int len);
this to symtablelist.c:
void SymTable_set_length(SymTable_T table, int len)
{
table->length = len;
}
and in main.c change this:
emptyTable->length = 3;
to this:
SymTable_set_length(emptyTable, 3);
although in this specific case passing the length as an argument to SymTable_new() is an obviously superior solution. Even more superior is not letting the user set the length of a linked list data structure at all - the length is the number of items in it, and it is what it is. It would make no sense to, for instance, add three items to the list, and then allow main.c to set the length to 2. symtablelist.c can calculate and store the length privately, and main.c can find out what the length is, but it doesn't make much sense for main.c to be able to set the length directly. Indeed, the whole point of hiding the members of a struct behind an opaque pointer like this is precisely to prevent client code from being able to mess with the data like that and breaking the data structure's invariants in this manner.
If you want to access the members directly in main.c, then you have to have the struct definition visible, there is no alternative. This will mean either putting the struct definition in the header file (recommended) or duplicating it in main.c (highly unrecommended).
In typedef symbolTable *SymTable_T;, you refer to a non-existent type symbolTable. In C (unlike C++) the type is named struct symbolTable. (Note: the question has changed to fix this since answering it.)
There's a second problem. In main.c the code will need to be able to see the definition of struct symbolTable for you to be able to refer to fields of emptyTable. At the moment, the definition is hidden in a .c file... it should be moved to the header.

Forward declaration error I'm having trouble making sense of

Header file declaration:
typedef struct Queue *QueueP;
C File implementation:
struct Queue
{
char *head;
char *tail;
QueueItemT item; //char typedef from the header file, not what's giving error
int SizeL;
int sizeP;
int QueueSize;
};
C main file:
#include <stdio.h>
#include <stdlib.h>
#include "Queue1.h"
int main()
{
struct Queue queue;
QueueP myQueue = &queue;
return 0;
}
I am getting errors on the following lines with the following messages respectively:
struct Queue queue;
^
Main : variable has incomplete type 'struct Queue'
typedef struct Queue *QueueP;
^
Header : note: forward declaration of 'struct Queue'
Any idea what might be causing these errors? I'm new to working with multiple files and header files in C, so I'm really having trouble wrapping my head around these errors. Any help would be great, thanks!!
You put structure definition into a c file. This is not how it works: you need to put the definition into the header.
This is because a definition of a struct is not an implementation. C compiler needs this information in order to process declarations of the struct correctly. A forward declaration lets you define a pointer to your struct; declaring a struct itself requires a full definition.
If you would like to keep the details of your struct private, put it into a private header file. Include the public header file from your private header, too:
queue.h
typedef struct Queue *QueueP;
queue_def.h
#include "queue.h"
struct Queue
{
char *head;
char *tail;
QueueItemT item; //char typedef from the header file, not what's giving error
int SizeL;
int sizeP;
int QueueSize;
};
main.c:
#include <stdio.h>
#include <stdlib.h>
#include "queue_def.h"
Now your project should compile without problems.
Actually, the reason I was getting forward declaration problems was because I was trying to access the struct (that was declared in the .c file) from within the main file.
Not only was this bad programming practice, the desired feature of the project was that the end user (i.e. the person using the interface and implementation to build their 'main.c' file) should have no idea what kind of struct was being used, they should simply be able to build a queue with the functions given and not know what was going on behind the scenes.
D'oh!!!

typedef vs. no typedef with structs and enums in C

In C, is there any effective difference between declaring a struct as
typedef struct {...} Foo;
and
struct Foo {...};
I know the second requires you to prefix uses with struct, but what are the differences between these two definitions that I'll notice when writing or executing the program? What about with enums?
Update: please see comments attached to answer for clarification.
Original post.
Besides having to write "struct" everywhere, something else of note is that using a typedef will allow you to avoid subtle syntax errors when working with pointers:
Quote:
Typedefs can also simplify declarations for pointer types. Consider
this:
struct Node {
int data;
struct Node *nextptr;
};
Using typedef, the above code can be rewritten like this:
typedef struct Node Node;
struct Node {
int data;
Node *nextptr;
};
In C, one can declare multiple variables of the same type in a single
statement, even mixing pointer and non-pointers. However, one would
need to prefix an asterisk to each variable to designate it as a
pointer. In the following, a programmer might assume that errptr was
indeed a Node *, but a typographical error means that errptr is a
Node. This can lead to subtle syntax errors.
struct Node *startptr, *endptr, *curptr, *prevptr, errptr, *refptr;
By defining a Node * typedef, it is assured that all the variables
will be pointer types.
typedef struct Node *NodePtr;
...
NodePtr startptr, endptr, curptr, prevptr, errptr, refptr;
If you write
typedef struct {...} foo;
It saves you from having to write struct foo everywhere: you can just write foo.
(You get this notational convenience for free in C++ by the way).
I would look at this SO question and then summarize that there is no appreciable functional difference between struct { ... } and typedef struct { ... } although the latter may make your code less cumbersome and easier to understand if used correctly.

Why does "struct T* next" compile when T isn't an existing type?

I am using MinGW on Windows. I am building linked list and I am confused with this.
#include <stdio.h>
#include <stdlib.h>
typedef struct Data
{
int x;
int y;
struct BlaBla * next; /*compiles with no problem*/
}List;
int main(void)
{
List item;
List * head;
head = NULL;
return 0;
}
I now that struct can't have struct variable(object, instance of that struct), but can have pointer of that struct type. Didn't know that pointer can be pointer of unexisting type. struct BlaBla * next;(not for linked list, it must be struct Data * next but mean general talking)
Yes, you can, because then the compiler, upon encountering the unknown type name for the first time, assumes that there's somehwere a struct type definition with this name. Then it will forward-declare the struct name for you, let you use it as a pointer, but you can't dereference it nor can you do pointer arithmetic on it (since it's an incomplete type).
The compiler will accept code such as your example:
typedef struct Data
{
int x;
int y;
struct BlaBla * next; /*compiles with no problem*/
}List;
This is okay because the size of pointers is known to the compiler, and the compiler is assuming that the struct will be defined before it is dereferenced.
Because the compiler acts this way, it's possible to do this:
typedef struct Data
{
int x;
int y;
struct Data * next; /* points to itself */
} List;
However, if you were to include the struct inline, like this:
typedef struct Data
{
int x;
int y;
struct BlaBla blaStruct; /* Not a pointer. Won't compile. */
}List;
The compiler can't work out how big struct Data is because it doesn't know how big struct BlaBla is. To get this to compile, you need to include the definition of struct BlaBla.
Note that, as soon as you need to access the members of struct BlaBla, you will need to include the header file that defines it.
It depends on what you mean by "unexisting". If you haven't even declared BlaBla, you'll get an error.
If you've declared it but not yet defined it, that will work fine. You're allowed to have pointers to incomplete types.
In fact, that's the normal way of doing opaque pointers in C.
So, you might think that this is invalid because there's no declaration of struct BlaBla in scope:
typedef struct Data {
struct BlaBla *next; // What the ??
} List;
However, it's actually okay since it's both declaring struct BlaBla and defining next at the same time.
Of course, since definition implies declaration, this is also okay:
struct BlaBla { int xyzzy; };
typedef struct Data {
struct BlaBla *next; // What the ??
} List;
In order to declare a variable or field of a given type, pass one as a parameter, or copy one to another of the same type, the compiler has to know how many bytes the variable or field occupies, what alignment requirements it has (if any), and what other pointer types it's compatible with, but that's all the compiler needs to know about it. In all common dialects of C, a pointer to any structure will always be the same size and require the same alignment, regardless of the size of the structure to which it points or what that structure may contain, and pointers to any structure type are only compatible with other pointers to the same structure type.
Consequently, code which doesn't need to do anything with pointers to a structure except allocate space to hold the pointers themselves [as opposed to the structures at which they point], pass them as parameters, or copy them to other pointers, doesn't need to know anything about the structure type to which they point beyond its unique name. Code which needs to allocate space for a structure (as opposed to a pointer to one) or access any of its members must know more about its type, but code which doesn't do those things doesn't need such information.

Any way in C to forward declare struct in header without having to use pointer in other files?

Suppose I have this in list.h:
typedef struct list_t list_t;
typedef struct list_iter_t list_iter_t;
list_iter_t iterator(list_t *list);
and then define them in list.c:
typedef struct node_t {
...
} node_t;
struct list_iter_t {
node_t *current;
// this contains info on whether the iterator has reached the end, etc.
char danger;
};
struct list_t {
...
}
list_iter_t iterator(list_t *list) {
list_iter_t iter;
...
return iter;
}
Is there anything I can do aside from including the struct declaration in the header file so that in some file test.c I can have:
#include "list.h"
void foo(list_t *list) {
list_iter_t = iterator(list);
...
}
Like maybe tell the compiler the storage size of list_iter_t somehow? It's inconvenient to have to use a pointer (not because it's a pointer, but for other reasons), but at the same time I would like to hide the implementation details as much as possible.
The succinct answer is "No".
The way you tell the compiler the size of a struct is by telling it the details of how the struct is structured. If you want to allocate an object, rather than a pointer to the object, the compiler must know the complete type of the object. You also can't access the members of a structure via a pointer to the structure if the type is incomplete. That is, the compiler must know the offset and type of the member to generate the correct code to access someptr->member (as well as to allocate somevalue or access somevalue.member).
It is possible to tell the compiler the size of the structure, using a dummy definition like:
struct node_t {
char dummy[sizeof(struct { ... })];
};
(with the proper definition instead available to the implementation file).
Formally this causes undefined behaviour; it is likely to somewhat work in practice, though.
You are probably best off just including the proper structure definition though, and leaving a comment to the effect that code should simply not touch the internal members.

Resources