I'm new to structures in c, I've been researching the difference between the . operator, and the -> operator. But I can't seem the find resources that explain what I want to know. So, why if I make structure without typedef, can I use it directly such as "header.first = x", and not having to say "struct header varName"? Also, what is the difference between the . and -> in this example, because it seems in this case I can use them interchangeably.
#include <stdio.h>
#include <stdlib.h>
typedef struct node{
int data;
struct node* next;
}node;
struct header{
int count;
node *first;
}header;
int main()
{
node *curptr = (node*)malloc(sizeof(node));
printf("%p\n",curptr);
header.first = curptr;
printf("%p\n",header.first);
header.count = 10;
printf("%i\n\n\n",header.count);
node* current = (node*)malloc(sizeof(node));
current->data = 5;
current->next = NULL;
printf("%i\n",current->data);
printf("%p",current);
}
struct header { ... } header; is simultaneously creating the struct type (struct header) as well as creating a global variable (named header, of type struct header). It is equivalent to doing:
struct header { ... };
struct header header;
When you write header.first = x, what you're doing is just modifying the global object named header.
typedef struct node { ... } node; is simultaneously creating the struct type (struct node) as well as a typedef to it (node). It is equivalent to doing:
struct node { ... };
typedef struct node node;
As for . vs ->: a->b is equivalent to (*a).b. It's just syntactic sugar.
struct in c is a place in memory which is big enough to keep data for all its fields. As with any other objects in 'c' you have a choice to use it as a variable or use a pointer to it. A pointer is essentially a memory address of this variable.
Also, every variable in 'c' has a type. The latter behaves like a template for creating variables and check their usage.
So, in the following example you create a struct type struct header and describe what it contains.
struct header{
int count;
node *first;
};
Now, using the type, you can create the variable named my_header:
struct header my_header;
or, as in your example, variable header.
struct header header;
As in you example you can combine both into a single statement.
Now, if you created a variable of type 'struct header', you can access its members using the . operator. The following operator will cause 'c' to access member count of your struct variable. It will calculate correct place in memory to put '10' into it.
header.count = 10;
as for pointers, you can create a variable which will keep an address to your object. In 'c' it needs to know what type of object it points to. So, the pointer ptr in the following example is assigned address & of the variable header.
struct header *ptr = &header;
Now you can use the pointer to access fields in the header, but it requires a different syntax ->. so, the following statement will be equivalent to the previous one:
ptr->count = 10;
Note that in both cases '10' was assigned to absolutely the same object, field of the variable 'header'.
Also to make life easier ant to stop typing struct every time, you can use the typedef operator to declare a named type, i.e.
typedef struct node myNodeType;
typedef struct node node;
now you have to 'named' types: myNodeType and node which are the same. you can use them to declare variables and pointers:
myNodeType var1; // variable
node *next; // pointer.
and as in case with variable declaration, you can combine it with struct declaration as in your example.
And malloc just allocates a chunk of dynamic memory and returns its address, aka pointer to it. so, node* current = (node*)malloc(sizeof(node)); just assigns address of allocated memory to the pointer current.
Hope it helps a bit.
Related
Why I can compile below code without any declaration?
struct node *n;
int main()
{
return 0;
}
I did'nt include any header.
Is this normal?
The pointer definition acts as a forward declaration of struct node. Using such a declaration is allowed as long as the pointer isn't dereferenced before the actual struct definition appears.
This is necessary to allow constructs like this:
struct list_node {
int value;
struct list_node *next;
};
This is a typical definition of a node in a linked list. The next field is of type struct list_node *, but at this point struct list_node has not yet been fully defined. If such forward declarations were not allowed, such constructs would not be possible.
You can also use such a pointer to pass to a function and get a value returned. For example:
struct node *n = new_node();
set_node_value(n, 1);
These two function could be defined in a separate source file where the full definition of struct node is known. The structure in this case is an opaque type that users of a library don't need to know the details of.
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).
struct node
{
int data;
node* pointerToNextNode;
};
Here pointerToNextNode is the type of struct node, and it is declared inside the struct.
How does the struct know the type of next pointer of its own type - when it itself hasn't been formed yet?
There is no keyword extern used. How does this work?
It doesn't need to know the structure, it's enough to know the type name, namely struct node — and that has already been defined.
Same result you can obtain by forward type declaration:
struct node; // declare the struct not defining it
struct node *pointer; // declare variable
void foo()
{
if(pointer != NULL) // OK, we use the pointer only
if(pointer->x == 0) // invalid use - struct contents unknown yet
return;
}
struct node { // supply a definition
int x;
};
void bar()
{
if(pointer != NULL)
if(pointer->x == 0) // OK - struct contents already known
return;
}
Here pointerToNextNode is the type of struct node
No, it's not. It's of type struct node *
struct node* pointerToNextNode; allocates memory for a pointer variable of type struct node.
It does not allocate memory for struct node, so, till point, it does not need to know about the size and representation of struct node. Only the (data)type name is sufficient.
Also, it's worthy to mention, without a typedef in place, node* pointerToNextNode; should not be valid. It should be written like below
typedef struct node node;
struct node
{
int data;
node* pointerToNextNode;
};
BTW, private: is not C thing, if i'm not wrong.
for me this doesn't compile using CC -- and exactly because of what you said.
you would have to use struct node * to make the compiler aware you want memory for a pointer
The follwing declaration is valid.
struct node
{
int a;
struct node *next;
};
However, when we define the following, it gives error.
"error: field ‘next’ has incomplete type"
Why is it so?
struct node
{
int a;
struct node next; /* Not a pointer */
};
node in struct node is a "struct tag", which at the point you write it creates an "incomplete type": a struct variable which is not at this point declared, but not defined. The type is not complete before the final }; of your struct.
In C, an incomplete type can be referenced even before it is fully defined, by using a pointer to that type. You can however not allocate a variable (instance) of that type, because the actual struct definition is yet to be defined. (It works exactly like abstract base classes in C++, if you are familiar with those.)
So when you write
struct node {
int a;
struct node *next;
};
the row struct node *next means "here is a pointer to a struct node, even though I have no idea how that type is defined yet". But you cannot declare a variable of type struct node inside the struct definition of that very same type, simply because you cannot use something before you have created it.
You can't have structure that contains itself as a member:
struct node
{
int a;
struct node next;
};
Think about this question: if it is possible, what is the size of such structure? struct node contains struct node next as a member, then the member next would contain a member of type struct node as well, and so on and on and on... The size would be infinite.
Your second declaration would define a struct which is infinitely deeply nested, which is impossible.
This is the same case as with forward declaration of class/struct type:
struct node;
struct node* node_ptr; /* is valid */
struct node node_instance; /* is invalid */
So struct node; basically says: hey there is a structure defined somewhere outside this file. The type is valid, pointers may be used, but you cannot instantiate the object.
This is because the size of the pointer is known and is specific to the target architecture (e.g. 32 or 64-bit). The size of the structure is unknown until declared.
When you declare the type completey, then you will be allowed to declare the object of that type:
struct node {
int a;
struct node* b; /* this will work, but the size of struct is unknown yet */
}
struct node* node_ptr; /* this works always with full and forward declarations */
struct node node_object; /* now, the size of struct is known, so the instance may be created */
it should be like this:
struct node {
int a;
struct node *next;
};
this works,
but
struct node {
int a;
struct node next;
};
cannot be understood by the compiler as node becomes recursive structure, and the compiler does not know how much memory to allocate for node.
However, if you use a pointer, it understands that the size of a pointer is equal to size of the memory to be addressed, and hence reserves that space, regardless of if node is a complete struct.
Pointer store address, struct has structure. If declared like struct it would be recursive and infinite. If declared like pointer it refers to other structure somewhere else.
Infinite nodes inside a node? Does that make sense? What will be the size of "struct node"?
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.