I'm having a hard time understanding the typedefs in this C structure.
typedef struct node {
int value;
list rest;
} node;
typedef struct node *list;
What's the difference between the "node" typedef declaration and the "list" declaration? Why is list prefaced as a pointer? Isn't "node" a pointer as well? Why can't I simply say "typedef struct node list" and omit the asterisk? I've been searching everywhere and I can't really find a satisfactory answer.
The first typedef defines node as an alias for struct node, to allow you to refer to it simply as node without writing struct node every time (in C "regular" type names and struct names live in two different namespaces). It's equivalent to:
struct node
{
int value;
struct node* rest;
};
typedef struct node node;
The second typedef, instead, defines list as an alias for node *, i.e. defines the type list as a pointer to a node structure.
(by the way, personally I find that this is very bad style: hiding pointers inside typedefs is almost always a bad idea; one can argue that a pointer to the first element in a list could be identified as the list, but the usage of list even for the rest pointer is IMHO not very nice)
node is not a pointer; it is a struct. list is a typedef for a pointer to node.
You typedef a struct in C to avoid typing struct node ... everywhere.
Whether or not this is good practice is questionable (most will agree that hiding a pointer type behind a typedef, unless it is truly opaque, is a bad idea), but that's the gist of it.
The first declaration says that a node is the structure. The second says that a list is a pointer to a node.
So, this would be proper code using those declarations:
list x;
node n;
x = &n;
Declaring an item using typedef struct node list is not correct. The typedef statement declares a new type. The keyword typedef is not part of the type's name.
node is a struct, which is (confusingly) named the same thing as struct node. list is a pointer to struct node. So the following are equivalent:
struct node *a;
node *a;
list a;
node is just a synonym for struct node
list is a pointer to a struct node (or node)
Each node instance contains a list pointer which enables you to build data structures such as (singly) linked lists, etc.
Related
I'm using this structure as a linked list:
typedef struct Node{
int value;
struct node_t* next;
}node_t;
And everything works fine until I put struct node_t* next before int value field, then I have a lot of trash values working with that structure.
Is it about wrong implementation or something else in the code?
You are calling your structure Node and defining a node_t type. Then you are using node_t as if it was the name of the structure and not the type.
Try this
typedef struct node {
int value;
struct node *next;
} Node;
Or
typedef struct node Node;
struct node {
int value;
Node *node;
};
If you call it struct Node, then
struct Node {
int value;
/* The compiler doesn't know what `struct Node' is yet */
struct Node *next;
/* But you can always declare pointers, even of types the compiler
* doesn't know everything about. Because the size of a pointer
* does not depend on the type of the pointee.
*/
};
In your example, it's even worse. You typedefed something that is a new type as the compiler understand it, to use it you MUST not use struct. The whole idea behind typedefing is that you DEFINED a new type, so suppose the following
typedef struct Node node;
then to declare a pointer of type node (note, again node IS A TYPE),
node *anode;
but you attempted something like
struct node *anode;
and it's wrong because there is no struct node in the code above, it's struct Node.
Another mistake in your code is that, the node_t type does not exist when the compiler finds the
struct node_t *next;
which is already wrong because if the type were defined before the struct which is possible like this
typedef struct Node node_t
it'd still be wrong to use struct on the node_t type, because for the compiler node_t is not a struct it's a new type, which in turn is simply an alias for struct Node.
Typedefing structures in my experience is more trouble than benefit anyway. And it's not so hard to type struct Something instead of just Something. It also has the benefit of being more explicit, so if another programmer reads your code, they will immediately know that Something is a struct.
Note: I deliberately changed the name to node because it's considered bad practice to suffix your own defined types with _t. It's not necessarily a bad thing, but over the years that I've been working with this I developed some habits and one of them is not to use _t as a suffix for my own defined types. Which by the way only exist in my code if they will improve readability a lot. Otherwise I simply use the name of the structure with the struct keyword.
You are using a non existing type node_t. The type doesn't exist because the type struct Node is not even complete and you are using it's alias. Another thing to remember while using typedefs with structures don't use struct keyword along with alias
eg.
/* This is correct */
typedef struct Node
{
int x;
struct Node *next;
} node_t;
/* while these are incorrect */
/* Prefixing struct keyword to a typedef'ed type */
struct node_t *listhead;
/* The type is inclomplete and you are using an alias of the type
which doesn't even exist */
typedef struct Node
{
int x;
node_t *next;
};
You are trying to create a pointer to the structure which you are yet to create. So, it should have been,
typedef struct Node{
int value;
struct Node* next;
}node_t;
This question already has answers here:
typedef struct vs struct definitions [duplicate]
(12 answers)
Closed 7 years ago.
I am getting a hard time understanding this sample of code:
typedef struct node
{
int data;
struct node * next;
} node;
typedef node * nodepointer;
So, we are building the struct node using typedef... I assume we are doing this in order to initialize the struct without the "struct" keyword being necessary.
I want to ask why in the struct definition we used the name "node" twice (at start and end).
Secondly what typedef node * nodepointer; points to. Is it necessary to use typedef in this case? Is this expression node * nodepointer; not equal?
First off, let's be clear here: a typedef isn't a declaration of a variable. It simply aliases a new type name to an existing type specifier.
typedef <type specifier> new_type_name;
So what's going on here can certainly be deceiving to the untrained eye.
struct node itself is a struct called node with the two properties int data and a struct node *next.
I'll go more into next in a moment, but for now this is simple enough.
Then, the surrounding typedef takes that struct and gives it the name node. Why is this, you might ask?
This is due to the fact that in C (unlike C++) using structs by their tag name requires prefixing the type with struct.
struct Foo {
// ...
};
Foo bar; // ERROR
struct Foo bar; // OK
Using a typedef, we alias the struct with a typename, called node. This example should make it a bit more clear.
typedef struct Foo {
// ...
} FooType;
Foo bar; // ERROR
struct Foo bar; // OK
FooType bar; // OK
struct FooType bar; // ERROR
Keep in mind you can define structs without tags, and thus typedef them.
typedef struct {
// ...
} FooType;
FooType bar; // OK
Though I'll explain why you can't do this in your example.
The property struct node *next in your example is an incomplete type. Incomplete types, simply put, are types that have been declared (given a name and a type, i.e. struct node;), but not defined (given a 'body', i.e. struct node { int foo; };).
Incomplete types cannot be used until they are defined, unless you're pointing to them.
struct Foo;
struct Foo bar; // ERROR: Foo is not defined.
struct Foo *bar; // OK - it's just a pointer. We know the size of a pointer.
struct Foo {
// ...
};
struct Foo bar; // OK - it's defined now.
So by the type struct node *next is declared, we already have the declaration of struct node but not the definition, which makes a pointer to struct node possible.
You can also infer, too, that using struct node directly would not work:
struct node {
struct node next; // ERROR - `struct node` becomes infinitely big
struct node *next; // OK - a pointer is usually 4/8 bytes (we at least know its size at this point)
};
To answer your last three questions:
What [does] typedef node * nodepointer; [point] to[?]
Nothing. It's just an alias (a label, or a 'nickname') to another type. It simply says that the type nodepointer is really a node *.
This also means anything that requires a node * can thus use a nodepointer, and vice versa.
Is it necessary to use typedef in this case?
Not necessary, no. You could just as well use node * everywhere instead of nodepointer. Most coding standards frown upon typedefing types to their pointer types (like your example) because it adds confusion to the code base (as you have demonstrated by this very question! :))
Is [the] expression node * nodepointer; not equal?
Nope. Again, remember typedef simply specifies another way to reference the same type. It doesn't actually create any memory, rather gives a new name to an existing type.
This struct is self referential which means it contains a pointer to itself.
if you don't use tag node, How will you specify pointer type later. Hence first node is required
struct node {
struct node *ptr;
};
// you can do this way too
typdef struct node node;
The last node is required for completing the typedef.
By typedef node * nodepointer;, Now you can use nodepointer to mean node*. Wherever node* occurs, you can simply replace with nodepointer
Is it necessary to use typedef in this case?
It is upto you,
Is this expression node * nodepointer; not equal?
No, this only declares nodepointer to be pointer variable whereas typedef creates alias of type, node * by the name nodepointer.
The question is that you are doing two things at once: declaring struct type and typedefing that struct to a name.
For typedef the syntax is
typedef <some type> name;
where some type may be a simple type, like int, long, etc. or a complex one like struct foo, and this regardless of wether struct foo has been declared before or it's being declared at that very point.
So
typedef struct foo { int bar; } foo;
Corresponds to
typedef <some type> name;
where <some type> is struct foo { int bar; } and name is foo
As to the second question,
In this case <some type> is node * and name is nodepointer, so
typedef node * nodepointer;
is typedefing a nodepointer as a pointer to a node (which you have typedefd just before to be a struct node { ... })
typedef struct node
int data;
struct node * next;
} node;
The node in the first line is the tag of the structure.
The node in the last line is the name of the type.
These two do not have to be identical.
If you want them to be different the code will be as follows.
typedef struct helloNode
int data;
struct helloNode * next;
} node;
The name of the type is node. The name of the structure is helloNode
For a more technical explanation, these two nodes are in different namespaces. and can have different values.
From section 6.3 of http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf
If more than one declaration of a particular identifier is visible at any point in a
translation unit, the syntactic context disambiguates uses that refer to different entities.
Thus, there are separate name spaces for various categories of identifiers, as follows:
— label names (disambiguated by the syntax of the label declaration and use);
— the tags of structures, unions, and enumerations (disambiguated by following any32)
of the keywords struct, union, or enum);
— the members of structures or unions; each structure or union has a separate name
space for its members (disambiguated by the type of the expression used to access the
member via the . or -> operator);
— all other identifiers, called ordinary identifiers (declared in ordinary declarators or as
enumeration constants).
For the struct, you are defining your structure name (before the braces) and then the type name (after the braces):
typedef struct node {
int data;
struct node* next;
} node;
The next one creates another type, a pointer to nodes:
typedef node* nodepointer;
Both can now be used to create variables:
node myNode;
nodepointer aPtr;
Daleisha said correctly that you need the struct tag in order to declare the pointer next which points to just these structures. You cannot write that type name down before it is introduced. Another possibility is to forward-declare the struct:
struct node;
typedef struct node node;
struct node
{
node *next;
int i;
};
But that introduces rather more mentionings of one node or another.
As a side effect, introducing the struct tag "node" makes it possible to still write the normal struct node, which the typedef alone would not make possible.
The second typedef is also still a typedef, it doesn't introduce a variable but a type name. After all the declarations in your source snippet you can say
struct node *np1;
node *np1;
nodepointer np1;
These are all equivalent.
The co-existence of the two type names node and struct node is possible because "struct tags" (like the "node" in "struct node"), as they are called, are held separately from other names and can therefore be used to name something else, additionally, without collision. To typedef a struct so that the new type has the name of the struct tag is a common example, but the name "node" could be used for anything else instead (an int variable, whatever).
I am learning about uses of data structures and came across some doubts:
struct node
{
int data;
struct node *next;
}*head;
Question1: In the above structure, what does declaring a struct node *next within the structure mean?. And how is it different from simply declaring a pointer variable within structure as int *next
Question2: We can see that, at the end of the structure definition, a pointer *head is declared of type node and is used to access the structure members if I am right. Is this same as declaring it like this:
struct node *head;
Any help with this would be great. Thank you all in advance.
"struct node *next" declares a variable called next which points to a "struct node". In other words, a singly linked list.
You are correct in that the statement does two things:
Declares a struct called node (with an int called data and a
pointer to the next struct node)
Declares a variable called head pointing to the struct node.
These could have been done separately as follows:
struct node
{
int data;
struct node *next;
};
struct node *head;
This is very commonly how Linked Lists are declared in C. Recall — a linked list is a series of nodes which contain data as well as a link (in this case, a pointer) to the next node in the series.
So, each object of type struct node should contain a pointer to another struct node. This is characterized by declaring a field next in the struct with type struct node *.
As for your second question: the code you provided both defines struct node (allowing you to instantiate objects of type struct node), and declares a pointer to such a struct called head. You could certainly define the variable head the way you asked, but you would still need to define the struct somewhere earlier in the code. This is usually done in a separate header file, but could be done in the same .c source code file for brevity.
Now, note that both these methods will not actually create a struct node object. All you're doing is declaring a pointer to one. The object doesn't yet exist anywhere since you never allocated space for it. To do that, you'd need to use malloc:
struct node {
int data;
struct node * next;
} * head;
head = malloc(sizeof(struct node));
You could also declare a runtime stack instance of the struct, which just means you won't need to explicitly free the memory you allocated with malloc(). The memory allocated for the struct is deallocated when you return from the function, or when your program terminates if declared outside of any functions.
Declaring next as struct node *next means that it points to a struct node, presumably the next node in the list. If it were instead declared as int *next then it would point to an int, which it doesn't seem there's any need for.
The answer to question 2 is yes. They are simply combining the definition of struct node with the declaration of head. They could be split apart as you indicated.
struct node
{
int data;
struct node *next;
}*head;
Why do we have *head? And is this different (better?) than doing
typedef struct
{
int data;
struct node *next;
}head;
The first section defines a variable head which is a pointer to a struct node type. It can be NULL, indicating that your linked list has zero elements.
The second block just declares a type called head. It's not a variable at all. And it does not compile as the type of its next field, struct node, does not exist.
You probably wanted
typedef struct node {
int data;
struct node *next;
} node;
node *head;
This form declares 2 types, struct node and node (the same), and defines a variable head. I'd go for the 1st form without the typedef, as it's more simple, and you cannot refer to the typedef inside the struct's next field anyway.
The first version declares a type (struct node), and a variable head which is a pointer to struct node. All lists need a head, so that's helpful.
The second declares head as the type name for an (otherwise unnamed) struct. It won't actually compile, since the inner struct node *next refers to a type which doesn't exist.
In your first example, you define the struct but also declare the head variable to be a pointer to such struct.
In your second example (typedef) you just declare some type synonym (but
no variables!)
struct node
{
int data;
struct node *next;
}*head;
in the code above you have declare object head as a pointer so in order to access its element data you need to use -> operator that is for example head->data=4; and so on
you can create nodes to append the head pointer
typedef struct
{
int data;
struct node *next;
}head;
where as in this code every node that you create will be of head type it will create a problem when you delete the head node if you write linked list code for deleting head you are unable redefine the new head
where as in earlier code head being a pointer can be change by updating its next element in struct after updating the head->next in previous code we can then easily delete the previous head without losing the new head
the gdb debugger (and perhaps other debuggers)
can only see the contents/format of a struct that contains a tag name.
The use of a typedef hides the tag name and defines a new type.
however, gdb will not properly display the contents of any instance of the struct.
The correct way is:
struct tagname { ... };
Notice no struct name to clutter the symbol table and create confusion
Of course, then each defining instance of this struct needs to be written as:
struct tagname myName;
but that should not be a problem and adds the visible documentation
that myName is a struct
Along with the increased visibility of the struct, both to gdb and the reader
of the resulting code, any pointer to that struct should never be defined
as part of the struct definition. Such a formatting hides the
fact that such name is a pointer. rather declare an instance of a pointer as:
struct tagname * pMyStruct;
And, never use this syntax:
struct { ... } structName;
as that is a depreciated syntax
This is code for a linked list in the C programming language.
#include <stdio.h> /* For printf */
#include <stdlib.h> /* For malloc */
typedef struct node {
int data;
struct node *next; /* Pointer to next element in list */
} LLIST;
LLIST *list_add(LLIST **p, int i);
void list_remove(LLIST **p);
LLIST **list_search(LLIST **n, int i);
void list_print(LLIST *n);
The code is not completed, but I think it's enough for my question. Here at the end of struct node "LLIST" is used, and it's also used as a return type in the prototyping of the function list_add. What is going on?
That's a typedef. It's actually doing two things at once. First, it defines a structure:
struct node {
int data;
struct node *next;
}
And then does a typedef:
typedef struct node LLIST;
That means LLIST is a type, just like int or FILE or char, that is a shorthand for struct node, your linked-list node structure. It's not necessary - you could replace LLIST with struct node in all of those spots - but it makes it a bit easier to read, and helps hide the implementation from pesky end-users.
LLIST is just another type name for the struct that has been created. In general, the following format will create a type "NAME" that is a "struct x":
typedef struct x { ... } NAME;
C requires that you reference structs with a "struct" prefix, so it's common to introduce a typedef for less verbose mention.
That is, the declaration of your struct has two parts, and can be rewritten as such:
struct node {
int data;
struct node *next; /* pointer to next element in list */
};
typedef struct node LLIST;
So, LLIST is just another name for struct node (thanks Chris Lutz).
typedef creates a new "type" in your program, so the return value and types of parameters of those functions are just your struct. It is just shorthand for using struct node for the type.
If you were to create a new node, you could do it like this (using the type):
LLIST *node = malloc(sizeof(LLIST));
node->data = 4;
node->next = someOtherItem;
list_add(node, 1)
Also, with the function prototypes in your question, you don't really need the double pointers; since the data in your struct is just an int, you could do something like
LLIST *list_add(int data, int position);
then the list_add function would handle the allocation, copy the int into the struct and add it to the linked list.
Putting it in at a certain position is as simple as changing the next pointer in the node before it to the address of the newly allocated node, and the next pointer in the new node to point at the next one (the one the node before that one was originally pointing at).
Keep in mind that (given the rest of your function prototypes) you will have to keep track of pointers to every node you create in order to delete them all.
I'm not sure I understand how the search function will work. This whole thing could be implemented a lot better. You shouldn't have to provide the location of a node when you create it (what if you specify a higher number than there are nodes?), etc.
LLIST* is a pointer to a structure defined by the LLIST struct.
You should do
LLIST* myList = malloc(sizeof(LLIST)*number_of_elements);
to have some memory allocated for this list. Adding and removing items requires you to reallocate the memory using realloc. I've already written some piece of code for lists (made with arrays).
I might post the code as soon as I'm home, which is currently not the case.