So today I was watching The mind behind Linux | Linus Torvalds, Linus posted two pieces of code in the video, both of them are used for removing a certain element in a singly-linked list.
The first one (which is the normal one):
void remove_list_entry(linked_list* entry) {
linked_list* prev = NULL;
linked_list* walk = head;
while (walk != entry) {
prev = walk;
walk = walk->next;
}
if (!prev) {
head = entry->next;
} else {
prev->next = entry->next;
}
}
And the better one:
void remove_list_entry(linked_list* entry) {
// The "indirect" pointer points to the
// *address* of the thing we'll update
linked_list** indirect = &head;
// Walk the list, looking for the thing that
// points to the entry we want to remove
while ((*indirect) != entry)
indirect = &(*indirect)->next;
// .. and just remove it
*indirect = entry->next;
}
So I cannot understand the second piece of code, what happens when *indirect = entry->next; evaluates? I cannot see why it leads to the remove of the certain entry. Someone explains it please, thanks!
what happens when *indirect = entry->next; evaluates? I cannot see why it leads to the remove of the certain entry.
I hope you have clear understanding of double pointers1).
Assume following:
Node structure is
typedef struct Node {
int data;
struct Node *next;
} linked_list;
and linked list is having 5 nodes and the entry pointer pointing to second node in the list. The in-memory view would be something like this:
entry -+
head |
+---+ +-------+ +-------+ +-------+ +-------+ +--------+
| |---->| 1 | |---->| 2 | |---->| 3 | |---->| 4 | |---->| 5 |NULL|
+---+ +-------+ +-------+ +-------+ +-------+ +--------+
This statement:
linked_list** indirect = &head;
will make indirect pointer pointing to head.
entry -+
head |
+---+ +-------+ +-------+ +-------+ +-------+ +--------+
| |---->| 1 | |---->| 2 | |---->| 3 | |---->| 4 | |---->| 5 |NULL|
+---+ +-------+ +-------+ +-------+ +-------+ +--------+
^
|
+---+
| |
+---+
indirect
The while loop
while ((*indirect) != entry)
*indirect will give the address of first node because head is pointing to first node and since entry is pointing to second node the loop condition evaluates to true and following code will execute:
indirect = &(*indirect)->next;
this will make the indirect pointer pointing to the next pointer of first node. The in-memory view:
entry -+
head |
+---+ +-------+ +-------+ +-------+ +-------+ +--------+
| |---->| 1 | |---->| 2 | |---->| 3 | |---->| 4 | |---->| 5 |NULL|
+---+ +-------+ +-------+ +-------+ +-------+ +--------+
^
|
+---+
| |
+---+
indirect
now the while loop condition will be evaluated. Because the indirect pointer is now pointing to next of first node, the *indirect will give the address of second node and since entry is pointing to second node the loop condition evaluates to false and the loop exits.
The following code will execute now:
*indirect = entry->next;
The *indirect dereference to next of first node and it is now assigned the next of node which entry pointer is pointing to. The in-memory view:
entry -+
head |
+---+ +-------+ +-------+ +-------+ +-------+ +--------+
| |---->| 1 | |-- | 2 | |---->| 3 | |---->| 4 | |---->| 5 |NULL|
+---+ +-------+ \ +-------+ +-------+ +-------+ +--------+
*indirect \ /
+------------+
Now the next of first node is pointing to third node in the list and that way the second node is removed from the list.
Hope this clear all of your doubts.
EDIT:
David has suggested, in comment, to add some details around - why are the (..) parenthesis required in &(*indirect)->next?
The type of indirect is linked_list **, which means it can hold the address of pointer of type linked_list *.
The *indirect will give the pointer of type linked_list * and ->next will give its next pointer.
But we cannot write *indirect->next because the precedence of operator -> is higher than unary * operator. So, *indirect->next will be interpreted as *(indirect->next) which is syntactically wrong because indirect is a pointer to pointer.
Hence we need () around *indirect.
Also, &(*indirect)->next will be interpreted as &((*indirect)->next), which is the address of the next pointer.
1) If you don't know how double pointer works, check below:
Lets take an example:
#include <stdio.h>
int main() {
int a=1, b=2;
int *p = &a;
int **pp = &p;
printf ("1. p : %p\n", (void*)p);
printf ("1. pp : %p\n", (void*)pp);
printf ("1. *p : %d\n", *p);
printf ("1. *pp : %d\n", **pp);
*pp = &b; // this will change the address to which pointer p pointing to
printf ("2. p : %p\n", (void*)p);
printf ("2. pp : %p\n", (void*)pp);
printf ("2. *p : %d\n", *p);
printf ("2. *pp : %d\n", **pp);
return 0;
}
In the above code, in this statement - *pp = &b;, you can see that without accessing pointer p directly we can change the address it is pointing to using a double pointer pp, which is pointing to pointer p, because dereferencing the double pointer pp will give pointer p.
Its output:
1. p : 0x7ffeedf75a38
1. pp : 0x7ffeedf75a28
1. *p : 1
1. *pp : 1
2. p : 0x7ffeedf75a34 <=========== changed
2. pp : 0x7ffeedf75a28
2. *p : 2
2. *pp : 2
In-memory view would be something like this:
//Below in the picture
//100 represents 0x7ffeedf75a38 address
//200 represents 0x7ffeedf75a34 address
//300 represents 0x7ffeedf75a28 address
int *p = &a
p a
+---+ +---+
|100|---->| 1 |
+---+ +---+
int **pp = &p;
pp p a
+---+ +---+ +---+
|300|---->|100|---->| 1 |
+---+ +---+ +---+
*pp = &b;
pp p b
+---+ +---+ +---+
|300|---->|200|---->| 2 |
+---+ +---+ +---+
^^^^^ ^^^^^
The entry isn't really "deleted", it's just no longer in the list.
If this is your chain:
A --> B --> C --> D --> E --> ■
And you want to delete C, you're really just linking over it. It's still there in memory, but no longer accessible from your data structure.
C
A --> B --------> D --> E --> ■
That last line sets the next pointer of B to D instead of C.
Instead of looping through the entries in the list, as the first example does, the second example loops through the pointers to the entries in the list. That allows the second example to have the simple conclusion with the statement you've asked about, which in English is "set the pointer that used to point to the entry I want to remove from the list so that it now points to whatever that entry was pointing to". In other words, it makes the pointer that was pointing to the entry you're removing point past the entry you're removing.
The first example has to have a special way to handle the unique case of the entry you want to remove being the first entry in the list. Because the second example loops through the pointers (starting with &head), it doesn't have a special case.
*indirect = entry->next;
That just move it to the next node
You need to remove the entry one
So you have to point .. before entry node the next of the entry node
So your loop should stop before the entry
while ((*indirect)->next != entry)
indirect = &(*indirect)->next
(*indirect)->Next =entry-> next
I hope that help you
This example is both a great way of manipulating linked list structures in particular, but also a really excellent way of demonstrating the power of pointers in general.
When you delete an element from a singly-linked list, you have to make the previous node point to the next node, bypassing the node you're deleting. For example, if you're deleting node E, then whatever list pointer it is that used to point to E, you have to make it point to whatever E.next points to.
Now, the problem is that there are two possibilities for "whatever list pointer it is that used to point to E". Much of the time, it's some previous node's next pointer that points to E. But if E happens to be the first node in the list, that means there's no previous node in the list, and it's the top-level list pointer that points to E — in Linus's example, that's the variable head.
So in Linus's first, "normal" example, there's an if statement. If there's a previous node, the code sets prev->next to point to the next node. But if there's no previous node, that means it's deleting the node at the head of the list, so it sets head to point to the next node.
And although that's not the end of the world, it's two separate assignments and an if condition to take care of what we thought of in English as "whatever list pointer it is that used to point to E". And one of the crucial hallmarks of a good programmer is an unerring sense for sniffing out needless redundancy like this and replacing it with something cleaner.
In this case, the key insight is that the two things we might want to update, namely head or prev->next, are both pointers to a list node, or linked_list *. And one of the things that pointers are great at is pointing at a thing we care about, even if that thing might be, depending on circumstances, one of a couple of different things.
Since the thing we care about is a pointer to a linked_list, a pointer to the thing we care about will be a pointer to a pointer to a linked_list, or linked_list **.
And that's exactly what the variable indirect is in Linus's "better" example. It is, literally, a pointer to "whatever list pointer it is that used to point to E" (or, in the actual code, not E, but the passed-in entry being deleted). At first, the indirect pointer points to head, but later, after we've begun walking through the list to find the node to delete, it points at the next pointer of the node (the previous node) that points at the one we're looking at. So, in any case, *indirect (that is, the pointer pointed to by indirect) is the pointer we want to update. And that's precisely what the magic line
*indirect = entry->next;
does in the "better" example.
The other thing to notice (although this probably makes the code even more cryptic at first) is that the indirect variable also takes the place of the walk variable used in the first example. That is, everywhere the first example used walk, the "better" example uses *indirect. But that makes sense: we need to walk over all the nodes in the list, looking for entry. So we need a pointer to step over those nodes — that's what the walk variable did in the first example. But when we find the entry we want to delete, the pointer to that entry will be "whatever list pointer it is that used to point to E" — and it will be the pointer to update. In the first example, we couldn't set walk to prev->next — that would just update the local walk variable, not head or one of the next pointers in the list. But by using the pointer indirect to (indirectly) walk the list, it's always the case that *indirect — that is, the pointer pointed to by indirect — is the original pointer to the node we're looking at (not a copy sitting in walk), meaning it's something we can usefully update by saying *indirect = entry->next.
This will be much easier to understand if you rewrite
indirect = &(*indirect)->next;
As
Indirect = &((*indirect)->next);
The while loop will give us the address of a next pointer belong to some node of which the next pointer is pointing to the entry. So the last statement is actually changing the value of this next pointer so that it doesn’t point to the entry anymore.
And in the special case when the entry is head, the while loop will be skipped and the last line change the value of the head pointer and make it point to the next node of the entry.
Related
I'm trying to delete nodes from a simply linked list on C, when I delete any other node except the first it works fine, but when I try to delete the first node the whole list messes up, I've tried different solutions and I have the same outcome, I don't know what to do anymore
One of my tries was this:
void deleteClient (client **p, int n){
client *t = *p;
if (t){
while (t && t->id != n)
t = t->next;
if (t){
client * ax = t;
t = t->next;
free(ax);
}
}
}
The other one was this
void deleteClient (client **p, int n){
client *t = *p;
if (t)
if (t->id == n){
client * ax = *p;
*p = (*p)->next;
free(ax);
return;
}
else{
while (t->next && t->next->id != n)
t = t->next;
if (t->next){
client * ax = t->next;
t->next = t->next->next;
free(ax);
}
}
}
But in both versions of the code it only deletes fine from the second node onwards, while messing up the whole list if I try to delete the first node.
You can eliminate testing for multiple cases (is node the 1st, if not the 1st, etc..) by simply using a pointer-to-pointer to node to hold the current node and a pointer to the next node, e.g.
/** delete node with value n from list (for loop) */
void deleteClient (client **p, int n)
{
client **ppn = p; /* pointer to pointer to node*/
client *pn = *p; /* pointer to node */
for (; pn; ppn = &pn->next, pn = pn->next) {
if (pn->id == n) {
*ppn = pn->next; /* set address to next */
free (pn);
break;
}
}
}
This approach is detailed in Linus on Understanding Pointers
The first question that comes to me, when dealing with your problem is: If you have defined an interface to your function that receives a pointer to a client by reference, why don't you get profit from that fact and use it to modify the received pointer? (I was astonished about this, because the first thing you do, in the function is to dereference it, and use a normal pointer, and you don't touch the original pointer received anymore) If you pass a pointer to the first node, you'll never have access to the pointer variable, and you'll not be able to change its value, and so, you'll never be able to unlink the first element, and it is because of that, that you need to access the pointer pointing to the first node (in order to be able to change it). Very good at passing the pointer by reference, but bad as you didn't know why.
(pointer to 1st el.)
+-----+ +----------------+ +----------------+
--->| *p >---------->| client | next >------->| client | next >------.
+-----+ +----------------+ +----------------+ |
^ V
| NULL
+--|--+
| p | (reference to the pointer that points to the first element)
+-----+
As you move the pointer reference, you get up to this scenario:
+-----+ +----------------+ +----------------+
--->| *p >---------->| client | nxt >-------->| client | nxt >-------.
+-----+ +----------------+ +----------------+ |
^ V
,-----------------------' NULL
+--|--+
| p | (see how the reference points to the pointer, not to client node)
+-----+
From this scenario, with a reference pointed by &p, we need to make the value pointed by the pointer referenced to the next client node's nxt pointer, and not to the node itself. As here:
,---------------------------.
| |
+-----+ | +----------------+ | +----------------+
--->| *p >----' | client | nxt >-----+-->| client | nxt >-------.
+-----+ +----------------+ +----------------+ |
^ ^ =====
| | ===
+--|--+ +-|--+ =
| p | | q | (q points to the client node, instead)
+-----+ +----+
In this graph, q is a node pointer we use to link to the client node we are going in order to free() after it has been unlinked. So, your first approach can be turned into this:
void deleteClient (client **p, int n)
{
/* first advance the reference to the n-esim pointer,
* (zero meaning the first node) We decrement n after
* checking, and test goes on while *p is also non null
*/
while (*p && (*p)->id != n)
p = &(*p)->next; /* move the reference to a reference
* to the pointer in the next node. */
client *q = *p; /* temporary link to the node to be
* freed */
if (q) { /* if found */
*p = q->next; /* make *p point to the next node. */
free(q); /* free the client node */
}
}
The way to call this routine should be:
client *list;
/* ... */
deleteClient(&list, 3); /* delete node with id == 3 */
The statement p = &(*p)->next; needs some explanation:
*p is the address of the client node that the pointer referenced by p points to.
(*p)->next is the next pointer of the node the pointer referenced by p points to.
&(*p)->next is the address of that pointer.
So we make p to point to the address of the next pointer of the client node pointed to by the referenced pointer *p.
NOTE
The reason your code messes up the whole list when you delete the first node is that you make the pointer (the initial pointer to the first node) to point to the second, but that pointer is local to your function and, as you never modify the pointer passed by reference (you modify the copy you make as soon as you get into the function, it is never modified above it), it continues to point to the (now free()d) node, so this makes the mess (not only you have a pointer pointing to an invalid address, you have leaked the rest of the nodes ---as the next field of the pointed node can have been changed by free() as a result of managing the returned memory chunk---) :)
Finally, you have a complete example here, that you can checkout from github.
I have some questions regarding the definition of a linked list as it was defined in my class.
This is what was used:
typedef struct node_t {
int x;
struct node_t *next;
} *Node;
Now, I understand that this way we created a shorter way to use pointers to the struct node_t. Node will be used as struct node_t*.
Now, say we want to create a linked list. For example:
Node node1 = malloc(sizeof(*node1));
Node node2 = malloc(sizeof(*node2));
Node node3 = malloc(sizeof(*node3));
node1->x = 1;
node1->next = node2;
node2->x = 4;
node2->next = node3;
node3->x = 9;
node3->next = NULL;
This is roughly how I imagine this (The circles represent the structures):
Now I know it's wrong, but I can't understand why. We have a pointer, node1, that points to our structure. Then, we point at node2, which points at another structure and so and so on.
Another things is, I can't understand how is it possible to have the longer arrows in the picture. Shouldn't we only be able to point to a structure from each lower part of the circle, and not to a pointer to a structure? How is this possible?
If anyone here could make things a little clearer it would be hugely appreciated. Thank a lot.
You have three linked nodes, and additional local pointers pointing to them.
The nodes don't know anything about those local pointers though, even if it is often convenient to use their names to refer to the nodes.
Instead, they know the next node in the sequence, respectively the last node knows none.
Put another way, your image is flat-out wrong.
+---+------+
node1 --> | 1 | next |
+---+-|----+
|
v
+---+------+
node2 --> | 4 | next |
+---+-|----+
|
v
+---+------+
node3 --> | 9 | NULL |
+---+------+
Assignment is a transitive operation. So,
node1->next = node2;
would mean that node1->next points to whatever node2 was pointing to. And, in particular, node1->next does not point to node2 itself.
Each of node1, node2, and node3 name a variable that is a pointer.
node1 node2 node3
+---+ +---+ +---+
| * | | * | | * |
+ | + + | + + | +
v v v
+---+---+ +---+---+ +---+---+
| 1 | * --> | 4 | * --> | 9 | * --> NULL
+---+---+ +---+---+ +---+---+
typedef struct node_t {
int x;
struct node_t *next;
} *Node; /* <-- don't typedef pointers */
Simply use Node instead of Node * and then allocate with:
Node *node1 = malloc(sizeof(*node1));
Why? Somebody looking at your code 100 lines below the declaration of your typedef will not inherently know whether Node is a type, or whether it is a pointer-to-type. This type of confusion will only grow as your code grows in size. Review: Is it a good idea to typedef pointers?.
(note: good job using the dereferenced pointer to set the typesize in sizeof)
A Linked List
A linked list is simply a clever data structure that allows you to iterate over a number of independently allocated nodes. Each node contains some data and then a pointer to the next node in the list, or NULL if that node is the final node in the list.
(for a doubly-linked list, you simply add a prev pointer that also points to the node before the current node in the list. You also have circular lists where the last node points back to the first allowing iteration from any node to any other node in the list regardless of which node you begin iterating with. For a doubly-linked circular list, you can iterate the entire list in both directions from any node)
In your case, your list is simply:
node1 +-> node2 +-> node3
+------+ | +------+ | +------+
| data | | | data | | | data |
|------| | |------| | |------|
| next |--+ | next |--+ | next |---> NULL
+------+ +------+ +------+
Where your data is a single integer value and your next pointer simply holds the address of the next node in your list, or NULL if it is the final node in the list. Adding your data, your list would be:
node1 +-> node2 +-> node3
+------+ | +------+ | +------+
| 1 | | | 4 | | | 9 |
|------| | |------| | |------|
| next |--+ | next |--+ | next |---> NULL
+------+ +------+ +------+
When creating a list, the first node is usually referred to as the head of the list and the last node the tail of the list. You must always preserve a pointer to the head of your list as that pointer holds the beginning list-address. For efficient insertions into the list, it is also a good idea to keep a pointer to the tail node so you can simply insert the new node without iterating over the list to find the last node each time, e.g.:
Node *newnode = malloc(sizeof(*newnode)); /* allocate */
newnode->next = NULL; /* initialize next NULL */
tail->next = newnode; /* assign to tail */
tail = newnode; /* set new tail at newnode */
Lists are fundamental to C, there are many used in the Linux kernel itself. Take the time to understand them and how to write them in the differing variants. You'll be glad you did. Lastly, don't forget to write a simple function to free your list when you are done (and free the data as well if it is allocated). A simple free_list function would be:
void free_list (Node *list)
{
while (list) {
Node *victim = list; /* separate pointer to node to free */
list = list->next; /* can you see why you iterate next... */
free (victim); /* before you free the victim node? */
}
}
Let me know if you have further questions.
I study electronics engineering and I'm learning C as my first language. I've been following IIT C Programming course, and it often takes me a little more time to understand the program when pointers are involved.
I'm learning about linked lists right now, I'll put part of the code then tell you guys what I'm having problem with. I'll not put everything because I don't think it will be necessary.
typedef struct node_type {
int data;
struct node_type *next;
} node;
typedef node_type *list;
list head, temp;
char ch;
int n;
head = NULL;
scanf("%c", &ch);
while (ch == 'Y' || ch == 'y') {
temp = (list)malloc(sizeof(node));
temp->data = n;
temp->next = head;
head = temp;
scanf("%c", &ch);
I couldn't understand why the use of '->' when working with pointers to structs, I know now that temp->data = n; is equivalent to (*temp).data = n;. But I'm having problem with the syntax of the second expression and why using it gives access to 'data' inside the struct which 'temp' points to.
When declaring variables there's an order as seen here: http://ieng9.ucsd.edu/~cs30x/rt_lt.rule.html
I know that there's a precedence order for the operators. In declarations I read * as "pointer to". How should I read (*temp).data in the middle of the code (not declaration) ?
In the beginning of the course, Dr.P.P.Chakraborty says that * could be understand as "the content of", but it wouldn't make sense in this expression: "the content of temp..."
What is the meaning of the operator * when not used in declarations?
The use of typedef follows the same rule of declarations like int *a[]? typedef int *a[] declares that the type 'a' is an array of pointers to int?
Appreciate any help.
The *temp means pointer dereference. So when you write (*temp).data the result of (*temp) has type node and not node*. Thus you can access the structure field using .
I know that there's a precedence order for the operators. In declarations I read * as "pointer to". How should I read (*temp).data in the middle of the code (not declaration) ?
"Retrieve the data member of the struct node_type instance that temp points to".
Graphically:
+---+ +---+
temp: | |-----> | | data <--- I want this
+---+ +---+
| | next
+---+
But I'm having problem with the syntax of the second expression and why using it gives access to 'data' inside the struct which 'temp' points to.
The expression temp has type "pointer to struct node_type". The unary * operator dereferences the pointer to access the pointed-to object. Thus, the expression *temp has type struct node_type.
Assume the following declarations:
struct node_type instance;
struct node_type *pointer = &instance;
After both declarations are complete, the following expressions are true:
pointer == &instance; // struct node_type * == struct node_type *
*pointer == instance; // struct node_type == struct node_type
pointer->data == (*pointer).data == instance.data; // int == int == int
pointer->next == (*pointer).next == instance.next; // struct node_type * == struct node_type *
Both of the member selection operators . and -> are grouped with the postfix operators, which have higher precedence than unary * - had you written *temp.data, the compiler would have parsed it as *(temp.data), which would mean "I want the thing that temp.data points to."
Graphically:
+---+ +---+
temp: | | data ------> | | <--- I want this
+---+ +---+
| | next
+---+
That's not what you want in this particular case.
As you discovered, temp->data is equivalent to (*temp).data - the -> operator implicitly dereferences the temp pointer. When dealing with pointers to struct and union types, you really want to use -> - it's less eye-stabby, and you're less likely to make a mistake with it.
Other places to watch out for precedence issues with pointers:
T *a[N]; // a is an N-element array of pointers to T
Graphically:
+---+ +---+
a: | | a[0] ----> | | some instance of T
+---+ +---+
| | a[1] --+
+---+ | +---+
... +-> | | some other instance of T
+---+
Each a[i] points to a distinct object of type T. To access the object, you'd dereference the array element - *a[i].
T (*a)[N]; // a is a pointer to an N-element array of T
Graphically:
+---+ +---+
a: | | -----> | | (*a)[0]
+---+ +---+
| | (*a)[1]
+---+
---
To access elements of the array, you need to deference the pointer a before you apply the subscript - you want to index into the thing a points to, so you need to write (*a)[i].
T *f(); // f is a function returning a pointer to T
The function f returns a pointer value; to access the thing being pointed to, you'd need to deference the return value:
x = *f();
Note that this is rarely done; you always want to do a sanity check on returned pointer values. You're far more likely to see:
T *p = f();
if ( p )
x = *p;
And finally,
T (*f)(); // f is a pointer to a function returning T
f points to a function - you must dereference f itself in order to execute the function:
x = (*f)();
You can get a clue of how to use each version of a and f based on its declaration.
I am having big problems understanding linked lists and I would be very thankful if someone could explain me the following.
Element_t *pushfront(Element_t *list)
{
if(list==0)
return allocate();
list->prev=allocate();
list->prev->next=list;
list=list->prev;
return list;
}
What here means list->prev->next=list ?
What means this: f->next->prev=f->prev?
I know that this is just a part from program code, but I hope someone can give me general meaning of these as simpliest as can?
The list has nodes that have references to the previous node and to the next node in the list.
The function gets the first node of the list. So this first node does not have a previous node.
In this statement
list->prev=allocate();
a previous node is created because as it follows from the function name it push a new node at the beginning of the list.
In this statement
list->prev->next=list;
expression list->prev yields the address of the new created node. This created node shall point to the current first node of the list. Thus its data member next shall contain the address of the node list.
And this statement
list->prev->next=list;
does this.
It can be imagined simpler if to introduce an intermediate variable.
For example
Element_t *new_node = allocate();
list->prev = new_node; // list->prev=allocate();
new_node->next = list; //list->prev->next=list;
list = new_node; //list=list->prev;
return list;
As for this question
What means this: f->next->prev=f->prev?
then it looks like that the node f is removed from the list. Now its next node (f->next) will not point to f but will point to the preceding node of f.
Again it will be more clear if to introduce intermediate variables.
Element_t *previous_node_of_f = f->prev;
Element_t *next_node_of_f = f->next;
next_node_of_f->prev = previous_node_of_f; // f->next->prev=f->prev
If to add also a statement like this
previous_node_of_f->next = next_node_of_f;
then the node f will be fully removed from the list.
--------------------------------------------------------
| prev ^
| |
---------------------- ---------------------- ----------------------
| previous_node_of_f | | f | | next_node_of_f |
---------------------- ---------------------- ----------------------
| ^
| next |
-------------------------------------------------------
Here is your code with comments, which tell you what is happening.
Element_t *pushfront(Element_t *list)
{
if(list==0) // If the list is emtpy
return allocate(); /* then you simply create a new node, which
represents your list and return it. The size of your list grew from 0 to 1.*/
list->prev=allocate(); /*If the list is not empty, you add a new node by creating it,
and then the prev pointer of the first element in the list (list->prev)
is set to this new element, as you want it to be first.*/
list->prev->next=list; /*Then you need to set the next pointer
to the element you just added. The new element is at list->prev,
so by list->prev->next, you just say, that the next element of the one
you just created is the element that was first before you added the new one*/
list=list->prev; /* Here you just set the new element as the head of the list*/
return list; /*And here you return the new list*/
}
Note, that your list is always passed just as a pointer to the first element, as that's all you need. You can then access all of the elements by next pointer, which is set for each element in the list.
Firstly the linked lists are linked each others with pointers. They are not in order in fact they are distributed on memory.
Let me get on your question-1 list->prev->next=list;
Here you are linking the previous node with the current node. This code means that link the next of previous to the current node. Then the previous node now linked with next pointer which is defined in structure.
Get the question-2 f->next->prev=f->prev;
I dont know where this is defined but here you are doing that a circled linked list. The last node linked to the first node by this code.
Element_t is a probably a typedef similar to the following:
typedef struct Element {
struct Element * next;
struct Element * prev;
void * data;
} Element_t;
Assuming this, your linked list basicly works like this:
(list)
A B C
+----------+ +----------+ +----------+
| next=B |--->| next=C |--->| next=0 |
| prev=0 |<---| prev=A |<---| prev=B |
| data="A" | | data="B" | | data="C" |
+----------+ +----------+ +----------+
So now you want to add a new node N in front of A
(list)
N A B C
+----------+ +----------+ +----------+ +----------+
| next=A |--->| next=B |--->| next=C |--->| next=0 |
| prev=0 |<---| prev=N |<---| prev=A |<---| prev=B |
| data="N" | | data="A" | | data="B" | | data="C" |
+----------+ +----------+ +----------+ +----------+
so, 1. A->prev needs to be set to N and 2. N->next needs to set to A.
list->prev=allocate(); this allocates the new N and already assigns A->prev=N.
Next in line: list->prev->next=list: Read list->prev as the new node that just got alloced. Then it's N->next=A - the second step.
And your new element is linked in the list. Obviously, allocate() needs to initialize next and prev to NULL.
What means this: f->next->prev=f->prev?
Depends on where it's written. Here, it's probably part of a function, that removes a node from the list.
Code to my linked list program: This is the code I saved on github
Knowing that pointers always accept the address of a variable. So if someone is writing just the name of array means that that is the address of the first element of the array. Ok that is right that's the address so we need not write an & in front of the array name. But if it were any other thing then we had to use the & sign. So in case of int we write that & sign in front of it. But what in the case of structure that is also a kind of variable of some custom made size?
The code for array may look like this:
int arr[] = {34,234,6234,346,2345,23};
int i;
for(i=0; i<(sizeof(arr)/arr); i++)
int *pointer = arr+i; //Now pointer can point to all the member array one by one
The code for an int may look like this:
int a = 5;
int *pointer = &a;
But if i have two pointers(head & temp) to structure of type struct node. Now I am writing the code for node.
struct node {
int data;
struct node *next; // this is pointer to next element in the Linked List
};
Now initially head is NULL i.e. not pointing to anything
head = NULL;
But on the first insertion to the linked list if do this:
head = temp; // both are pointers
knowing that head can only take the address coz its a pointer but temp is not an array so if write this writing temp doesn't mean its the address of that structure temp
Should I do this
head = &temp
to actually get the address of that temp structure(pointer)?
I get a feeling that we do head = temp and that valid cause like arrays temp is pointer of type structure node. So writing temp means just the address of the temp pointer in the memory. And Now head pointer is having the address of temp & pointing to what head has?
Is head pointing to address of temp or head has now address of temp. Pointing and having are different I guess.
To explain my comment, see the following crude drawings:
In the case of head = temp it will look something like
+------+
| temp | --\
+------+ \ +----------------+
>--> | your structure |
+------+ / +----------------+
| head | --/
+------+
That means that both head and temp points to the same place.
If you on the other hand do head = &temp (and the compiler allowed it), it will look like
+------+ +------+ +----------------+
| head | ---> | temp | ---> | your structure |
+------+ +------+ +----------------+
That is, head points to temp and not to your structure.
head and temp both are of type struct Node*. Assigning temp to head means head is pointing to the same location as that of pointed by temp. &temp is the address of the temp variable which is of pointer to struct NODE type, i.e struct Node**.
temp and &temp both are of different type. You compiler should raise awarning fo the assignment
head = &temp; // assigning incompatible pointer without cast
In case of single variable whether an int or char the address of operator & is used to reference that variable. In case of an array of integers, the name of the array arr[] i.e arr itself represents the address of the first element of the array. See below how the pointer arithmetic operation arrays internally do:
To reference the 'i'th element we write arr[i] = *(arr + i)
So, arr[0] = *(arr + 0) = *(arr)
But in your case, head and temp are pointers of the type struct node*. Using & operator to assign the address of temp to head will firstly won't be allowed by the compiler giving a cast error and moreover it will not serve your purpose either. What you should do is head = temp which will make head and temp point to the struct node.