Difference between these c struct declarations? - c

I have a code looking like this :
struct point {
int a;
int b;
}
which can be further used like this :
struct point p;
p.x = 10;
p.y = 5;
now I came to know that this can also be written like this :
typedef struct{
int x;
int y;
} point;
and can be used as point p
The confusion started when I started learning linked-list, this is the code I saw.
typedef struct node {
int val;
struct node * next;
} node_t;
I have a couple of questions:
If we can define the struct by simply using typedef struct { ... } node whats the use of writing typedef struct node {.....
The node_t at the end of the code is really confusing because from my understanding it has already defined a type node so we can call node x to create a node , then what's the need of the node_t or basically writing anything after the } what it means ?
shouldn't this work ?
typedef struct {
int val;
struct node * next;
} node;

If we can define the struct by simply using typedef struct { ... } node whats the use of writing typedef struct node {.....
The node_t at the end of the code is really confusing because from my understanding it has already defined a type node so we can call node x to create a node , then what's the need of the node_t or basically writing anything after the } what it means ?
In C, structures can have both tag and a typedef name. In the structure declaration:
typedef struct node {
int val;
struct node * next;
} node_t;
node is a tag and node_t is typedef name. Latter you can declare your structure variable either by using tag or typedef name.
struct node *new_node; // OK
node_t *head; // OK
In fact, the tag and typedef name can even be same, although that's not required:
typedef struct node {
int val;
struct node * next;
} node;
shouldn't this work ?
typedef struct {
int val;
struct node * next;
} node;
No. This will not work . Why?
The reason is that, when a structure has a member that points to the same kind of structure, as node does, we are required to use a structure tag. Without the node tag, we would have no way to declare the type of next.
Suggested reading: As Op is asking for good resource on data structure. Here you can go:
Tutorial: Introduction to Data Structures.
Book: Classic Data Structures.

The third block of code, which you seem to have a question about, has a redundant identifier.
typedef struct node {
int val;
struct node * next;
} node_t;
is identical to
struct node{
int val;
struct node * next;
};
typedef struct node node_t;
They're identical, but merged into the same line. The syntax around a typedef is
typedef [original name] [new name];
Normally, when we typedef a struct, the ONLY way to reference it afterwards would be the typedeffed name (in the first code example, you could only access it by node_t) while a slightly more redundant declaration allows for accessing by the "struct node" variable type too.
To answer your other question the node_t that confused you is what you can refer to the struct as... for example
node_t node1;
struct node node2;
Are the two valid declarations for a node struct.

Here, you can also use 'struct p' by typedefing it using 'struct p typedef P;'. It sometimes makes me confused when typedef a complex function pointer.
I don't know the reason why the C std. support such a syntax sugar.

Here is my explanation.
struct
{
int i;
};
declares an unnamed structure and apparently there is no real usage of this. Please correct me if I am wrong.
struct
{
int i;
} T;
now T is an object in the given scope and type is unnamed.
struct TT
{
int i;
} T;
declares a structure TT and an object T. You can use TT to create more objects. The best way to think about this is, just consider struct TT{ int i} as a single type such as double.
typedef struct TT
{
int i;
};
has the same meaning as (at least in nowadays compiler. I'm not sure about the older ones)
struct TT
{
int i;
};
and
typedef struct
{
int i;
} TT;
declares a type TT (not an object) for the given structure as you are using typedef int Int;
Hope this resolves the mess.

Related

What exactly does typedef struct node {...} Node; represent?

Please view this block of code:
typedef struct node
{
int data;
struct node *next;
}
Node;
In this code, is Node synonymous to struct node, as defined by typedef, or is node synonymous to struct? If the latter is the case, then is struct node *next; equivalent to struct struct *next;?
Am I overcomplicating things?
When you use typedef you create an alias of some type.
So yes, Node is an alias for struct node.
Also, the code you have is equivalent to
struct node
{
int data;
struct node *next;
};
typedef struct node Node;
The typedef is not part of the structure definition, it part of the Node definition.
Node is synonymous to struct node. Thats why (for your example) instead of using
struct node* p;
One can use
Node* p;
In the C grammar structures are defined the following way
struct-or-union-specifier:
struct-or-union identifieropt { struct-declaration-list }
So to refer this structure specifier you need to use its name.
You may declare variables the following way
struct node
{
int data;
struct node *next;
} Node;
Here Node is an object of type struct node. In turn struct node is a type specifier of variable Node.
You may omit the identifier in a structure specifier. In this case the structure is called unnamed structure. However using such a structure you can not refer to it itself inside its definition. For example you may not write
struct
{
int data;
struct *next;
^^^^^^^^^^^^^
} Node;
because it is unknown what structure is referred to here.
You may use unnamed structures as members of other structures. In this case such a structure is named anonymous structure and its members become members of the enclosing structure.
For example
struct A
{
struct
{
int x;
int y;
];
int z;
};
This structure A has three members x, y, and z.
When the storage-class specifier is used then the declarator is an identifier to be a typedef name that denotes the type specified for the identifier.
Thus in this declaration
typedef struct node
{
int data;
struct node *next;
} Node;
Node is not already an object. It is a type name that denotes struct node.
So from now you may use type name Node instead of the type specifier struct node
you no longer have to write struct all over the place. That not only saves keystrokes, it also can make the code cleaner since it provides a smidgen more abstraction.
Stuff like
typedef struct {
int x, y;
} Point;
Point point_new(int x, int y)
{
Point a;
a.x = x;
a.y = y;
return a;
}
typedef struct node
{
int data;
struct node *next;
}
Node;
This can be understood simply by
struct node
{
int data;
struct node *next;
};
typedef struct node Node;
struct [structure tag or label] {
member definition;
...
member definition;
} [one or more structure variables];
new variable can be defined as :
struct label <variable>;
or if you use typedef struct label need not to be repeated every time to define new structure variable
i.e
typedef struct label Node;
Now Node can be use to define new similar type of variable.

Structure pointer forward declaration?

I am new to c programming and creating linked list data structure, MY teacher gave me some code which seems a bit confusing :
typedef struct node *ptr;
ptr start,current;
typedef struct node{
int value;
ptr next;
};
This code works fine and using the other functions i can create a linked list , my confusion is that, when i change the code like this:
node *start;
node *current;
typedef struct node{
int value;
node *next;
};
it doesn't work .What is wrong with this code why cant i forward declare the node pointers anymore.
typedef struct node *ptr;
ptr start,current;
typedef struct node{
int value;
ptr next;
};
The typedef for the struct itself won't work this way, I guess you're missing a node at the end (It's missing the identifier of the newly defined type).
At this point, I'd tell your teacher to please not confuse everyone by typedefing a pointer type. It's widely common to have the pointer type modifier visible on every usage, just to make it obvious it is a pointer. But now to the actual answer:
node *start;
node *current;
typedef struct node{
int value;
node *next;
};
Start at the first line: you use node here as a type identifier. But you didn't tell the compiler yet what kind of type node should be. In fact, what you're actually missing is a forward declaration. It would work like the following:
/* forward-declare "struct node" and at the same time define the type
* "node" to be a "struct node":
*/
typedef struct node node;
/* now use your type by declaring variables of that type: */
node *start;
node *current;
/* finally fully declare your "struct node": */
struct node {
int value;
node *next;
};
Or, without the typedef, that easily confuses a beginner:
struct node; /* forward declaration (not strictly necessary in this little example) */
struct node *start;
struct node *current;
struct node {
int value;
struct node *next;
};
What you're doing in the second case is not a forward declaration. It's attempting to use a type (node) without defining it.
The first case doesn't quite work either. It gives the following warning:
warning: useless storage class specifier in empty declaration
That is because you're not assigning a type alias for struct node. You'd have to do it like this:
typedef struct node{
int value;
ptr next;
} node;
Now, you can use node in place of struct node.

What is the purpose of the first "node" in the declaration: "typedef struct node { - - - } Node;"?

I am studying code examples from my professor in order to become better acquainted with linked data structures.
In our linked-list.c example the professor defines a type Node as follows:
typedef struct node {
int data;
struct node *next;
} Node;
What's the point of the lower case node? I was under the impression that you could just write, for example:
typedef struct {
int data;
struct node *next;
} Node;
and then use Node as its own type. Does it have something to do with the fact that if you don't include a lower case node then when the compiler is evaluating the code it will not be able to understand what is meant by "struct node *next"?
Take a look at this declaration:
struct node {
int data;
struct node *next;
};
typedef struct node Node;
This can be combined into a single statement (simplifying a declaration):
typedef struct node {
int data;
struct node *next;
} Node;
Does it have something to do with the fact that if you don't include a lower case node then when the compiler is evaluating the code it will not be able to understand what is meant by "struct node *next"?
Yes.
The node in struct node is the tag of the struct type. If you give the struct a tag, you can refer to that type from the moment on the tag is complete, so in
typedef struct node {
int data;
struct node *next;
} Node;
the struct node *next; declares a member next that is a pointer to the struct type being defined. The typedef name Node is not available before the ; ending the definition is reached.
If you omit the tag, you cannot refer to the type being defined in any way before the typedef is complete, so in
typedef struct {
int data;
struct node *next;
} Node;
the line struct node *next; declares a new, unrelated, incomplete struct type with the tag node that next points to.
That's valid, but nothing about struct node is known (unless it is defined somewhere else), so you can't use the next pointer without casting it to a pointer to a complete type everywhere (not quite everywhere, Node foo; foo.next = malloc(12); etc. would still work).
He is defining a temporary name for the node because he is using a well know technique to avoid writing struct node on the declaration of each struct object.
If he would just do:
struct node {
int data;
struct node *next;
};
you would have had to use:
struct node* node;
to declare a new node. And to avoid that you would have to define later:
typedef struct node Node;
in order to be able to declare objects like the following:
Node* node;
In the end:
typedef struct node {
int data;
struct node *next;
} Node;
Is just a shortcut for struct node { ... }; in addition to typedef struct node Node;.
Here struct node is a type like int
and Hence
struct node {
int data;
struct node *next;
}NodeVar;
means you are declaring a single variable Node of struct node.
like int intVar;
typedef is to make your code understandable.
so that when you use
typedef struct node Node;
you can use the same declaration as
Node NodeVar;
Consider this code:
#include <stdio.h>
typedef struct {
int data;
struct node *next;
} Node;
int main()
{
Node a, b = {10, NULL};
a.next = &b;
printf("%d\n", a.next->data);
}
This won't compile. The compiler has no idea what a struct node is, other than it exists. So you might change the definition in the struct to Node *next;. The typedef isn't in scope before it's declared, so it still won't compile. The simple answer is to do as he said, use the node tag after struct, and it works fine.
The lower case 'node' is a structure type... i.e. a struct node { stuff } is a node structure containing stuff.
On the other hand, the upper case "Node" is a completely new data type which refers to a 'struct node'
Generally (though in C++ I think you can), you cannot pass around a "node" in a C program... for example as an argument to a function. Rather, you would have to pass a 'struct node' as your argument...
// this will throw a syntax error because "node" is not a data type,
// it's a structure type.
void myFunc( node* arg );
// while this will not because we're telling the compiler we're
// passing a struct of node
void myFunc( struct node* arg );
// On the other hand, you *can* use the typedef shorthand to declare
// passing a pointer to a custom data type that has been defined
// as 'struct node'
void myFunc( Node* arg );

Useless variable name in C struct type definition

I'm implementing a linked list in C. Here's a struct that I made, which represents the linked list:
typedef struct llist {
struct lnode* head; /* Head pointer either points to a node with data or NULL */
struct lnode* tail; /* Tail pointer either points to a node with data or NULL */
unsigned int size; /* Size of the linked list */
} list;
Isn't the "llist" basically useless. When a client uses this library and makes a new linked list, he would have the following declaration:
list myList;
So typing llist just before the opening brace is practically useless, right? The following code basically does the same job:
typedef struct {
struct lnode* head; /* Head pointer either points to a node with data or NULL */
struct lnode* tail; /* Tail pointer either points to a node with data or NULL */
unsigned int size; /* Size of the linked list */
} list;
You need to give a struct a name if you will reference it in its declaration.
typedef struct snode {
struct snode* next;
struct snode* prev;
int id;
} node;
But if you won't reference the struct inside it you dont need to give it a name.
EDIT
Notice that typedef is and struct are two different statements in C.
struct is for creating complex types:
struct snode {
struct snode* next;
struct snode* prev;
int id;
};
Which reads like make a structure called snode that stores two references to itself (next and prev) and an int (id).
And typedef is for making type aliases:
typedef struct snode node;
Which reads like make a type alias for struct snode called node.
Yes, you are correct. It is only a matter of habit or convention to explicitly name the struct in addition to the typedef.
Note that there is little to no cost either way, since llist is not a variable and does not take up memory. It is like the difference between naming a variable i or index - the compiled form is the same, but one may be more readable than the other.
It's useless in that particular case but, if you wanted a pointer to that struct within the struct itself, it would be needed.
That's because the struct is known at the opening brace while the typedef isn't known until the final semicolon (simplistic, but good enough here).
So you would need it for something like:
typedef struct sNode { // structure can be used now
int payload;
struct sNode *next; // cannot use typedef yet
} tNode; // typedef can be used now
You could turn this around: not the structure tag, but the whole typedef is superfluous.
struct snode {
struct snode* next;
struct snode* prev;
int id;
};
Now you can declare a pointer with:
struct snode *ptr;
You can even declare an array of them:
struct snode mynodes[10];
You'll have to type the struct keyword, but that won't hurt the compiler or the human reader (look at that syntax highlighting!).
You could even declare a pointer to an unknown type (at this moment of compilation) using an incomplete type:
struct xnode *xptr=NULL;
That will come in handy when you want to create an API to some library, where the actually implementtation of the library is not known to the caller:
struct gizmo *open_gizmo(char *path, int flags);
int fiddle_with_gizmo(struct gizmo *ptr, int opcode, ...);
Et cetera. A typedef would force the header file to "broadcast" all its internals to the caller, even if that is not needed.

creating Typedef pointers to Typedef structs in C

Have a question about typedef in C.
I have defined struct:
typedef struct Node {
int data;
struct Node *nextptr;
} nodes;
How would I create typedef pointers to struct Node ??
Thanks !
You can typedef them at the same time:
typedef struct Node {
int data;
struct Node *nextptr;
} node, *node_ptr;
This is arguably hard to understand, but it has a lot to do with why C's declaration syntax works the way it does (i.e. why int* foo, bar; declares bar to be an int rather than an int*
Or you can build on your existing typedef:
typedef struct Node {
int data;
struct Node *nextptr;
} node;
typedef node* node_ptr;
Or you can do it from scratch, the same way that you'd typedef anything else:
typedef struct Node* node_ptr;
To my taste, the easiest and clearest way is to do forward declarations of the struct and typedef to the struct and the pointer:
typedef struct node node;
typedef node * node_ptr;
struct node {
int data;
node_ptr nextptr;
};
Though I'd say that I don't like pointer typedef too much.
Using the same name as typedef and struct tag in the forward declaration make things clearer and eases the API compability with C++.
Also you should be clearer with the names of your types, of whether or not they represent one node or a set of nodes.
Like so:
typedef nodes * your_type;
Or:
typedef struct Node * your_type;
But I would prefer the first since you already defined a type for struct Node.

Resources