I am having issues with pointer use in C - c

Could someone please explain to me how this code works. I tried writing it out and wrapping my head around it, but I am still lost.
When you are setting next->prev = prev what is the difference in value between next->prev and prev? aren't they the same value? same question for the next line as well.
I tried writing out a ListElement struct to try to help understand but I am still confused. Any answer or help would be greatly appreciated, or any other references that can make me understand. I am a visual learner so if you happen to know a good visualization of this, I would appreciate it.
int unlink(ListElement *element)
{
ListElement *next = element->next;
ListElement *prev = element->prev;
next->prev = prev;
prev->next = next;
return 0;
}

The first two assignments define "connections" to the previous, 1, and next, 3, node.
ListElement *next = element->next; // next connects current node to the one that follows
ListElement *prev = element->prev; // prev connects current node to the one that precedes
that is why they are called prev and next. The other two lines are re-wiring the prev and next nodes such that they skip the current node, i.e.
you are accessing the preceding and following nodes's members (with the same names) via the connections defined above:
next->prev = prev; // now node: 3 is connected to node: 1
prev->next = next; // now node: 1 is connected to node: 3
Note: remember that each node has two pointers named prev and next

Let's say you have a linked list:
1->2->3
Pointer head points to the head of the list.
head->next points to the element 2.
*
1->2->3
You call method unlink on it:
unlink(head->next);
By passing head->next, you passed element 2 to the function.
It will then keep pointers to the next and previous elements:
ListElement *next = element->next; //3
ListElement *prev = element->prev; //1
It will then proceed to unlink this element:
next->prev = prev; // now next (3) has a previous pointer to 1
prev->next = next; // now prev (1) has a next pointer to 3
Now 2 is unlinked and can be reused/deleted.

This code removes an element from a doubly linked list.
It is done by assigning the "next" pointer of element's previous element directly to element's next element. Vice versa, the "prev" pointer of element's next element is set to element's previous element.
This has the effect that element is removed from the linked list.
Hope this helps.
When you are setting next->prev = prev what is the difference in value
between next->prev and prev? aren't they the same value?
This only sets the pointer next->prevto the value of prev, meaning that the next element's prevpointer points to the same address as the variable prev.

This function basically unlinks passed list element.
No, they don't have the same value.
prev->next is the next pointer of the node before element in the list.
next is defined as element->next, so it a pointer to the node after element in the list.
So, with prev->next = next, you basically set the next pointer of the node before element to the node after element.
Analog explanation for next->prev = prev.
This diagram from the UCLA illustrates the behavior of your function:

Let's draw a diagram of the doubly linked list's elements:
|ITEM0 | |ITEM1 | |ITEM2 |
| next->ITEM1 | | next->ITEM2 | | next->NULL |
| prev->NULL | | prev->ITEM0 | | prev->ITEM1 |
Let's say we want to unlink ITEM1, we save the next element into a variable called next, that's the *next = element->next; part, so now next = ITEM2, then we save the previous: *prev = element->prev;, so now prev = ITEM0. Now, we set the previous of the next element (aka previous of ITEM2) to prev (which is ITEM0) and set the next of the previous (aka next of ITEM0) to next (which is ITEM2), so we end up with this:
|ITEM0 | |ITEM1 | |ITEM2 |
| next->ITEM2 | | next->ITEM2 | | next->NULL |
| prev->NULL | | prev->ITEM0 | | prev->ITEM0 |
Note how we moved the next pointer of ITEM1 into the next pointer of ITEM0, and the prev pointer of ITEM1 into the prev pointer of ITEM2.
At this point, we can free ITEM1 (as nothing points to it), and we have just unlinked it from the linked list!

Related

I'm confused on why this Linked List implementation works

I've just recently gotten into linked lists and I'm adding my own "add to end" function.
void insert_at_end(Node** head, Node* node)
{
Node* temp;
temp = *head;
if (temp == NULL) // linked list is empty
{
*head = node;
}
else
{
while (temp->pNext != NULL)
{
temp = temp->pNext;
}
temp->pNext = node;
}
}
Originally I was doing temp != NULL instead of temp->pNext != NULL because I thought that way it would take me to the very LAST node, since it stops looping when temp still has data before it reaches NULL. Wouldn't temp->pNext != NULL stop at the 2nd to last node? Since it stops looping when it realizes that the last nodes next pointer is NULL, it does not travel to that node?
Thanks guys, If I need to clear anything up from that word vomit let me know.
Wouldn't temp->pNext != NULL stop at the 2nd to last node?
No. Here is the pictorial representation for ease of understanding.
With temp != NULL, temp will be pointing to NULL:
+---+ +---+ +---+
| 1 |--->| 2 |--->| 3 |---> NULL
+---+ +---+ +---+ ^
|
temp
As you see temp is iterating until it becomes NULL, at which point you cannot attach anything to the final node because you're past it.
With temp->pNext != NULL, temp will be pointing to last node.
+---+ +---+ +---+
| 1 |--->| 2 |--->| 3 |---> NULL
+---+ +---+ +---+
^
|
temp
Here temp will iterate till its next node is NULL. That means you're pointing to the final node and you can use that pointer to adjust that node to point to a new one with temp->pNext = node:
+---+ +---+ +---+ +---+
| 1 |--->| 2 |--->| 3 |--->| 4 |---> NULL
+---+ +---+ +---+ +---+
^
|
temp
As an aside, you may also want to add the extra safety of ensuring the node you're given points to NULL, on the off chance the caller may forget to do that. That's as simple as adding this line to the start of the function:
node->pNext = NULL;
Let's make some analogy.
Each node is a station.
NULL is your stop station.
while (temp->pNext != NULL) { temp = temp->pNext; } means drive and visit each station until reach the stop station.
When you reach the stop station, an additional station is needed to be added by temp->pNext = node;
Now the former stop station followed by the new added stop station(implicitly the new NULL) is not a stop station, but the penultimate station to be visited.
have a reference for simple linked list concept
let us take an example
consider
struct node
{
int data;// data which you want to feed.
struct node *next;// gona hold the address of the next data, so that link can be established
}*root,*p; // root is the starting reference to your linked list
case 1: you dont insert any element and your linked list is empty. Now when you insert a new data 10.it will check for any data in the global pointer reference to your linked list, if, the pointer seems to be NULL, then it means your liked list is empty.The memory stack will be created like this.
10
1000
10 is the data, 1000 is its address.
case 2: adding an element at its back.you want to add, data 20 to your linked list.you will be looking whether the linked list is empty or not first, using your global linked list address reference(it will be a pointer variable, holding your linked list 1st address, as per your code)
now when we see root->data is not null 1000->data is 10
we go for root->next which is null, which we come to know that this is the last node. 1000->next is NULL
and we insert the new node address to the root->next so that a link is created to the newly inserted node.
stack will be created like this
10 20
1000 1004
case3: now you want to add another data say 30 to the end of list again. just follow the same as case 2.
check for the node which is currently null, i.e root->next == NULL,
for this you use a loop to find the node which is currently in last, like this.
struct node *temp; // creating a temp node which will be the new node we will insert
temp = (struct node *)malloc(sizeof(struct node));// allocating the size for the temp node, same as the size of previous nodes.
p = root;// i am giving my starting address to pointer p, i traverse the node with pointer p only, since i dont want to loose my root starting address.
while(p->next != NULL)// checking for the last node
p = p->next;// if last node not found, just move to next node, and see whether it is last node or not
p->next = temp;// if last node is found, put the address of newly created temp node to the node previously found last in the linked list.
temp->data = element;// feeding data to the temp node.
temp->next = NULL;// keeping temp node as last, it is necessary to say temp wont has any more node connected.
NOTE dont think this is just a temp node, and will disappear once we come out of function, it is playing with pointer, so it wont destroyed until, the owner wont destroy it.
flow will be
newly created temp address is 1008
1000->next is 1004
1004->next is NULL
so, 1004->next will hold 1008 now
then,1008->data will be 30
then, 1008->next will be NULL
stack will be created like this
10 20 30
1000 1004 1008

Hassle in Linkedlist in C

Suppose I have 3 nodes already in the list (i.e. 10 , 20). And I want to insert 30. So wrote as below
struct node *p,*temp;
p=start;
temp=(struct node*)malloc(sizeof(struct node));
temp->info=30;
temp->link=NULL;
while(p-link!=NULL)
{
p=p->link;
}
p->link=temp;
It worked perfectly until I do this: while(p!=NULL) rest is same..
Similarly in case of showing the node I wrote as follows
while(p!=NULL)
{
printf("%d \n",p->info);
p=p->link;
}
This also worked fine until I changed it to: while(p->link!=NULL)
I want to know what is happening why is not working? Give me the reason why we are using while(p!=NULL) in case of showing the all the data and while(p->link!=NULL) in case of inserting any node?
Before the first while loop, you've got something like this. Two nodes (not three as you state) in a linked-list, pointed to by start and a new node, pointed to by temp:
start-->+---------+ +-->+---------+ +---------+<--temp
|info:10 | | |info:20 | |info:30 |
|link:xxxx|--+ |link:NULL| |link:NULL|
+---------+ +---------+ +---------+
To add the new node to the end of the list, you need to advance p from the first node (pointed to by start) until p points at the node whose link is NULL (i.e., until p->link!=NULL fails to be true):
start-->+---------+ +-->+---------+ +---------+<--temp
|info:10 | | |info:20 | |info:30 |
|link:xxxx|--+ |link:NULL| |link:NULL|
+---------+ +---------+ +---------+
^
|
p -+
Once you have found the last node, you then "plumb" in your new node to get a three-element list:
start-->+---------+ +-->+---------+ +-->+---------+
|info:10 | | |info:20 | | |info:30 |
|link:xxxx|--+ |link:yyyy|--+ |link:NULL|
+---------+ +---------+ +---------+
However, when you're printing all of the nodes, you start p at the first node (i.e. start) and print the details of every node until p has been set to NULL (i.e. p!=NULL fails to be true). If you stopped when p->link was NULL, you would not have printed the last node.
A linked list, in C is a struct that contains data and a pointer to the next element (and maybe a pointer to the previous element, but that doesn't seem to be your case). It would be something like this:
struct node {
int data; //could be any type
struct node *next;
};
To insert elements in the end of the list, you need to go to the end of it - when there is no next element. To do that, you check node->next == NULL. Then you make node->next = new_node
To find an element in the list, you need to loop for all elements until you find it. If the element doesn't exists in the list, you need to prevent the user from accessing an invalid element, so you test node == NULL to finish the loop safely. This case is also applicable if you want to just print all data in the list - you need to reach all elements, the test would be the same (if you were testing node->next == NULL, you would skip the last element).

Understanding code in c (linked lists)

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.

Linked List Explanation

I am new to C, i am trying to learn linked lists, can some one explain me the code below.
I understand some part of it but not all of it.
void deletefrombeginning( node **head, node **tail)
{
node *temp;
if(*head==NULL)
return;
temp=*head;
if(*head==*tail)
*head=*tail=NULL;
else
{
(temp->next)->prev=NULL; <-- there is where i get lost.
*head=temp->next;
}
free(temp);
}
(temp->next)->prev=NULL;
This line is making the prev pointer of what will be your new head NULL. So that when the second item in your linked list becomes the new head with:
*head = temp->next;
it has no prev pointer and is therefore the new head.
------ ------
| | <--prev--- | |
NULL <----- | temp | | node | -----> ...
| | ---next--> | |
------ ------
Short answer:
(temp->next)->prev=NULL; makes sure that node->prev doesn't
access invalid memory.
*head=temp->next; makes temp the new head of the list.
Long answer:
You are currently at temp.
You cannot delete temp first because you then would have broken links (what would node->prev point to?).
This means you have to first remove the links related to temp.
Since temp is the first node, temp->prev should point to NULL.
So (temp->next)->prev=NULL; is equivalent to node->prev = NULL;.
We cannot directly do node->prev = NULL; because we do not know node exists at this point.
*head=temp->next makes sure that the new list head is node (in my above ascii demonstration).
The next step then frees the memory used by temp.
Tip: In case you're nitpicky like me, you might want to assign temp to NULL right after you free it. This makes sure that you can never mistakenly access temp in the rest of your code. Memory can still be accessed in error even after freeing it.

How to remove a node any integer data

I am working on my homework but I really don't know how to remove a node with an integer data I already have a code for adding of nodes, I just need to remove nodes, or can you give me atleast an algorithm of it goes like this
addnode(root,5);
addnode(root,2);
addnode(root,6);
display(root);
removenode(root,5);
display(root);
removenode(root,6);
do you guys need code for my addition code? but our proff already gave us the code for showing the display of nodes ;
void display(struct node *head)
{
struct node *traverser;
traverser = head;
while(traverser!=NULL)
{
printf("%d\n",traverser->x);
traverser=traverser->next;
}
}
struct node
{
int data;
struct node *next
};
a question though what does traverser=traverser->next;
I assume you are dealing with a linked list. These are usually built up of entries that contain data and a link to the following name (thus the name):
struct node {
int data;
struct node *next;
}
As you can see, the link is a pointer in C. Which should point to the next entry. To start traversing a list, you usually have got a head.
If you want to remove an entry, you need to traverse the list and once you found the entry you want to remove, simply rearrange the pointers:
void removeEntry(int data, struct node *head) {
struct node *prev = NULL, *current = head;
while(current->data != data) {
prev = current; // current will always point to the entry in front of current
current = current->next;
if(current == NULL) // end of list and no match
return;
}
// now current is pointing to the entry you want to remove
// remove it just by rearrangeing pointers
prev->next = current->next;
free(current); // I assume you malloc'ed the memory
}
Note: Please note that I omitted errorchecking here. Also, sometimes the head is a fixed item in which no data is stored (would work in my case), sometimes head can contain data itself (in this case you need to check if the element you want to remove is the first element and relink head accordingly)
1)
you can delete the node from the linked list like(considering head is not dummy node i.e head also contains data)...
int flag=0;
if(head->data==data_todel) head=head->next; //if head contains the data
ptr=head;
while(ptr->next!=NULL && flag==0)
{
if(ptr->next->data!=data_todel)
ptr=ptr->next;
else
{
flag=1;
break;
}
}
if(flag) ptr->next=ptr->next->next;
you need to use two pointers to free the deleted node.
2)
+------+-------+ +------+-------+
| data1| next | | data2| next |
+------+-------+ +------+-------+
^ | ^
| | |
| +--------------+
+---------+
|traverser|
+---------+
after traverser=traverser->next
+------+-------+ +------+-------+
| data1| next | | data2| next |
+------+-------+ +------+-------+
| ^ ^
| | |
+--------------+ |
|
+---------+
|traverser|
+---------+
that means it is assigning the address of of the next node currently pointed by traverser.
a question though what does traverser=traverser->next;
It sets the pointer to the next element in the queue. Iterating in your while cicle until it reaches a null pointer (end of the queue).
(You didn't post the node structure declaration, so i'm just guessing)
The next field is the key in the linked list. Each element has a successor, that way the list is linked. So, when you traverse the list, you start at the first element head and move from one element to the next until there is no next element.
To remove an entry, you need to cycle through the list until you find that entry. Then, set the next variable of the previous entry to the next entry. That way, the element is removed from the list.

Resources