How to clear a linked list using double pointer? - c

Hi I'm trying to make a function that clears a linked list that *first will point to, then the node **first should be freed and the pointer *first set to NULL.
I'm having trouble grasping double pointers and can't get this to work correctly.

You have to move to the next list element before you delete the node. Otherwise you are accessing memory that has been freed.
while( *first != NULL )
{
temp = *first;
*first = temp->next;
free(temp);
}
Be aware that because you're trashing the whole list, *first is going to eventually be NULL. So you can use a single-pointer (just like temp) to traverse your list, and then set *first = NULL at the end. That saves an extra pointer indirection, which arguably is wasteful of CPU in this case.
[edit] What I mean is:
struct node *curr = *first;
struct node *prev;
while( curr != NULL )
{
prev = curr;
curr = curr->next;
free(prev);
}
*first = NULL;
Generally, I find that the less pointer dereferencing you have going on, the easier the code is to understand at a glance.

node* remove_node(node **double_pointer,int search_value)
//pass head of your node as a parameter to double pointer
{while(*double_pointer && **(double_pointer).value!=search_value)
{
double_pointer=&((**double_pointer)->next);
}
if(**double_pointer!=null)
{//lines below are to delete the node which contains our search value
node* deleted_node=*double_pointer;
*double_pointer=*double_pointer->next;
return deleted node;
}}

Related

Reverse fuction for singly linked list isn't working as it should

we've given a task to reverse a singly linked list and for some reason i struggling with it
its reversing as it should ,but the head that should be the tail just disappears and i can't figure why, even after debugging
'''
void Reverse(struct node *head) {
struct node *last = NULL;
struct node *current = NULL;
struct node *temp = NULL;
current = head;
while (current->next != NULL) { //getting ptr to last item of the list
current = current->next;
last = current;
};
current = head; //resseting the current ptr back to the head of the list
while (current->next->next != NULL) { //getting the current ptr to one before the tail item
current = current->next;
};
temp = last;
while (last != head) {
if (current->next == last) {
last->next = current;
last = current;
current = head;
if (last == head) {
head->next = NULL;;
head->data = temp->data;
head->next = temp->next;
break;
};
};
};
};
'''
I can't completely follow the logic in your code. You find the last and the second last element, and I will assume that head is some dummy element that you always have (because otherwise, not checking if it is NULL is a problem). After that, I am not sure what happens. You "flip" the last two links if you are looking at the head you update it? (You don't need to set head->next to NULL before you update it two lines later; that doesn't do anything).
Did you want to move current from the head and down to the one before last somewhere in the loop? I think that would work, but you would get a quadratic time algorithm.
If we assume that head is a dummy, so it doesn't have any elements to worry about, and we just want its next pointer to point to the reversed links, you should be able to do something like this:
void reverse(struct node *head)
{
struct node *next = head->next;
head->next = 0;
while (next) {
struct node *next_next = next->next;
next->next = head->next;
head->next = next;
next = next_next;
}
}
In the while-loop you can think of the code as pushing next to the front of the list pointed to by head->next and popping it off the current list (by setting next to next_next. When you reach the end of the list, head->next points to all the links, in reversed order. (I haven't tested the code, but I belive it should work).
If head is not a dummy node, you have to handle the special case that it is NULL, and you have to move its value. It makes things trickier if you have to do the latter, especially if you want to use the list generically, where the user is allowed to allocate links, and you might not know what data is in them (beyond that they have a link embedded in them). I would go for having a dummy link if you can, it makes everything simpler, not just reversal.
Of course, with doubly-linked lists it gets simpler still:
#define swap_p(x,y) \
do { struct node *tmp = x; x = y; y = tmp; } while(0)
void reverse(node *dummy)
{
struct link *p = dummy;
do {
swap_p(p->prev, p->next);
p = p->prev;
} while (p != dummy);
}
but that might not be what you want.
Don't know if that helps, but I hope it does a little at least.

A question about deleting a node in a linked list

Before calling the free(); function if I don't assign NULL value to the link part of the node that I want to delete, what will be the problem ? I reviewed some codes of deleting nodes in other websites, but I found no assignment of NULL value to the link part. They just called the free(); function. Please reply to remove my confusion. Thank you.
struct node
{
int data;
struct node * next;
}
struct node * head = NULL; //This is the head node.
/* Here some other functions to create the list */
/* And head node is not going to be NULL here, after creating the list */
void deleteFirstNode()
{
struct node * temp = head;
head = temp->next;
temp->next = NULL; //my question is in this line, is this line necessary?
free(temp);
}
No, the line
temp->next = NULL;
is not necessary. Any data in the node pointed to by temp will become invalid as soon as free is called, so changing any values inside that node immediately before they become invalid will have no effect.
This function can invoke undefined behavior when will be called for an empty list due to these statements
struct node * temp = head;
head = temp->next;
because in this case head is equal to NULL.
The function frees the memory occupied by an object of the type struct node. So there is no sense to change the deleted object. This statement
temp->next = NULL; //my question is in this line, is this line necessary?
is redundant.
It is the same as before deleting the node to write
temp->data = INT_MAX;
This does not influence on the list.
The function can look like
void deleteFirstNode()
{
if ( head != NULL )
{
struct node *temp = head;
head = head->next;
free( temp );
}
}
Also it is a bad idea to define function that depend on global variables. In this case you will be unable for example to create more than one list in the program. It is better when the pointer to the head node is passed to the function deleteFirstNode by reference.
In this case the function can look like
void deleteFirstNode( struct node **head )
{
if ( head != NULL )
{
struct node *temp = *head;
*head = ( *head )->next;
free( temp );
}
}
And the function can be called like
deleteFirstNode( &head );

Why does my code not insert a new node into this linked list?

I am new to programming. I just want to know why this doesn't work.
My understanding of pointers isn't clear, especially when using pointers across functions.
void append(struct Node** head_ref, float new_data)
{
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
struct Node *last = *head_ref; /* used in step 5*/
new_node->data = new_data;
new_node->next = NULL;
while (last != NULL)
last = last->next;
last = new_node;
return;
}
void append(struct Node** head_ref, float new_data)
{
while (last->next != NULL)
last = last->next;
last->next = new_node;
return;
}
In the first function the new data doesn't get included, I get only the original linked list.
But the second function works just fine. How does a double pointer work when inserting a new node in the beginning of the linked list? (I have seen answers regarding this question, but I am still confused)
In the first example, you move the pointer last until it points at a NULL location. Then, you set the pointer to new_node. However, at this point, last has no real association to your linked list. It is just a pointer to some memory. In the second example, the correct one, you iterate until you reach the tail of the linked list, where next of that node is NULL. Then, you set that next to new_node. There is now a new tail to the list, that is new_node.
Changing the local variable last does not change the value of the data member next of the previous (last) node.
To be more clear let's assume that the list is empty. Then you have to change the pointer referenced by this double pointer head_ref.
You declared a new pointer
struct Node *last = *head_ref;
The loop
while (last != NULL)
last = last->next;
is skipped because now already last is equal to NULL die to the initialization in the previous declaration. And then you changed this local variable last
last = new_node;
The original value of the pointer pointed by head_ref was not changed because last and *head_ref occupy different extents of memory. You changed the memory occupied by last but not changed the memory occupied by head_ref.
Also you should check whether a memory was successfully allocated.
The function can look the following way
int append( struct Node **head_ref, float new_data )
{
struct Node *new_node = malloc( sizeof( struct Node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = new_data;
new_node->next = NULL;
while ( *head_ref != NULL ) head_ref = &( *head_ref )->next;
*head_ref = new_node;
}
return success;
}
As for this loop (I think you wanted just to show the loop not a whole function)
while (last->next != NULL)
last = last->next;
last->next = new_node;
then you are changing the data member next of the previous (last ) node.
Though this loop will not work if initially head_ref is equal to NULL.

Linked Lists C Deleting Node

I'm just starting to learn linked lists and i was practicing by writing some basic functions such as add or delete. The program was working for some time but then i guess i did something and it starting giving me segmentation fault at my delete function which is this. The segmentation fault is in the while loop in if. Any idea why? Thanks in advance and sorry for my bad english :).
void deleteNode(struct node **first, int age)
{
struct node *tempNode;
if((*(*first)).age == age)
{
tempNode = *first;
*first = (*first)->next;
free(tempNode);
}
struct node *currentNode = (*first)->next;
struct node *lastNode = *first;
while(currentNode!=NULL)
{
//Segmentation Fault
if(currentNode->age == age)
{
tempNode = currentNode;
lastNode->next = currentNode->next;
free(tempNode);
}
lastNode = currentNode;
currentNode = currentNode->next;
}
}
The problem here is that you are referencing lastNode after it has been freed. If we look at the trace of the loop, you free tempNode, which you have assigned to currentNode, and then you set lastNode to currentNode. You want lastNode to point to the last valid node, so the update lastNode = currentNode is only valid if currentNode has not been freed.
In short, the fix is to only assign lastNode = currentNode if you don't remove the current node.
The trick with freeing nodes from a list is to get the information out of the node before you free it. Attempting to access memory that has been freed results in undefined behavior.
In this case you are only dealing with next, and you are tracking lastNode. So, lastNode->next is the logical currentNode.
In the beginning of your function, you account for the case that the first node matches age. However, if that is the case, the next node may also match age. So, your first matches age case also needs to be a loop.
Instead of writing two loops, use the concept of address of previous node's next to represent lastNode. This works well since first is already a pointer to a pointer to node.
struct node **lastNode = first;
while (*lastNode != NULL) {
struct node *currentNode = *lastNode;
if (currentNode->age != age) {
lastNode = &currentNode->next;
continue;
}
/* remove currentNode */
*lastNode = currentNode->next;
free(currentNode);
}

C Linked List copy segfault

I am rather new to C, and am working on copying a Linked List. It seg faults somewhere in the while loop, I think I am having some pointer troubles. Also, I'm not sure if I need to malloc each 'next' node. Do I? It makes sense for me to have to.
struct node* copyList() {
struct node* walker = head; // starting point to "walk" the list
struct node* temp;
temp = (struct node*)malloc(sizeof(struct node));
temp->data = walker->data;
while( walker != NULL ){ // done when we reach the node pointing to NULL
walker = walker->next; // advance walker to the next node in the list
temp = temp->next;
temp = (struct node*)malloc(sizeof(struct node));
temp->data = walker->data;
}
return walker;
}
The node strut is as follows
struct node {
int data;
struct node* next;
};
Suppose you reach last node..
Now inside loop , you increment walker..so now walker = NULL..
so this statement gives an error temp->data = walker->data..
Also you are just creating nodes and copying data not connecting your new linked list..
You need to maintain new Head pointer to return at the end
Keep reference to previous node so that you can link it to current node
Update the pointers
Change it along the lines of this..
struct node* copyList() {
struct node* walker = head; // starting point to "walk" the list
struct node* newHead=NULL,temp,prev=NULL;
while( walker != NULL ){ // done when we reach the node pointing to NULL
temp = (struct node*)malloc(sizeof(struct node)); //create new node
temp->data = walker->data; //copy data
if(prev==NULL) //if its first node
newHead = temp; //new head pointer
else
prev->next = temp; //else link to previous node
prev = temp; //update pointers
walker = walker->next;
}
return newHead;
}
Just where do you expect the value of temp->next in your loop to come from?
Also, to get a bit more meta, you might be vastly better off using e.g. std::list in C++ rather than implementing your own data structures like this. Even for experienced engineers, such efforts are notoriously error-prone.

Resources