I have two different linked lists, and I try to pop one node from the first linked list and to to the second linked list. My goal when calling the pop function (pop(Node * head)) is to update the new head and return to the popped node. However, what happens is that it turns to the popped node but the passed Node * head points to the popped element. Hence I cannot proceed. What is my problem with this function? I'm probably messing up with the pointers
Node * pop(Node * head)
{
Node * temp = head;
long val = temp -> value; //store the value before deallocating
head = head -> next;
free(temp);
return createNode(val);
}
//Code snippet where I call the pop function
if (currNode == NULL) {
headSublistPointers -> node = pop(tmpHeadOrigArr);
} else {
while (currNode -> next != NULL) {
currNode = currNode -> next; //go until the end of the linked list
}
currNode -> next = pop(tmpHeadOrigArr);
}
This function
Node * pop(Node * head)
{
Node * temp = head;
long val = temp -> value; //store the value before deallocating
head = head -> next;
free(temp);
return createNode(val);
}
does not make sense.
For starters the head shall be passed by reference
Node * pop(Node **head);
and secondly instead of freeing the popped node you could just return it setiing its data member next to NULL. Also in general the head node can be equal to NULL.
The function can look like
Node * pop( Node **head )
{
Node *current = *head;
if ( *head != NULL )
{
*head = ( *head )->next;
current->next = NULL;
}
return current;
}
Related
im trying to insert node to the begging of link list but the value from poiter to poiter isnt passing
i wrote a note ***** where the problem accure
void insertTolist(list* head, list* node)
{
list* current = head;
list* currentPlusOne = head->next;
while (current->next != NULL)
{
if (current->data<node->data && currentPlusOne->data>node->data)
{
current->next = node;
node->next = currentPlusOne;
break;
}
if (current->data<node->data && currentPlusOne->next == NULL)
{
current->next = node;
node->next = (list*)calloc(1, sizeof(list));
break;
}
if (current->data > node->data && currentPlusOne->data >node->data)// b c
{
node->next =current;
head = node;// ***the head doesnt chanching at the main***
break;
}
current = current->next;
currentPlusOne = currentPlusOne->next;
}
//printlist(head);
}
The function declared like
void insertTolist(list* head, list* node)
deals with a copy of the value of the pointer to the head node used as an argument. Changing the copy in this statement
head = node;
is not reflected on the value of the original pointer.
Moreover the function can invoke undefined behavior if the passed pointer is a null pointer at least due to this declaration
list* currentPlusOne = head->next;
Also this statement
node->next = (list*)calloc(1, sizeof(list));
does not make a sense.
You need either to pass the pointer to the head node to the function by reference through a pointer to it or to return from the function the pointer (possibly modified) to the head node and to assign its value to the original pointer.
If to use the first approach then the function will look enough simple.
void insertTolist( list **head, list *node )
{
while ( *head != NULL && !( node->data < ( *head )->data ) )
{
head = &( *head )->next;
}
node->next = *head;
*head = node;
}
and if in the caller the pointer head is declared like
list *head = NULL;
then the function is called like
insertTolist( &head, node );
where node is a pointer to the inserted node in the list.
When I run the program it works except when I delete a fairly large number such as 100 or above, whenever I input anything remotely as large as that number I get the Heap use after free error. The terminal is saying it is caused by line 53 in insert() which is this line, tail->next = newNode;. I know keeping head and tail pointers as global variables are not the best way to write it, but I will change it once I get this to work.
void insert(int nData) {
struct Node *newNode = (struct Node*)malloc(sizeof(struct Node)+10);
newNode->data = nData;
newNode->next = NULL;
if(checkDuplicates(nData)==1){
return;
}else{
if(head == NULL){
head = newNode;
tail = newNode;
}
else {
tail->next = newNode;
tail = newNode;
}
}
}
void delete(int n){
if(head -> data==n){
struct Node *tempHead = head;
head= head -> next;
free(tempHead);
return;
} else{
struct Node *current = head;
struct Node *prev = NULL;
while(current!=NULL&¤t->data!=n){
prev = current;
current = current -> next;
}
if(current==NULL) return;
prev->next = current->next;
free(current);
}
}
There is a possible case where tail->next = newNode would be executed on a freed node: that happens when earlier on you called delete and that deleted the tail node in the list. In that case your code does not adjust the value of tail.
So in delete change:
head = head -> next;
to:
head = head -> next;
if (head == NULL) {
tail == NULL;
}
And in the else block change:
prev->next = current->next;
free(current);
to:
prev->next = current->next;
if (tail == current) {
tail = prev;
}
free(current);
For starters the function insert can produce a memory leak because at first a memory is allocated
struct Node *newNode = (struct Node*)malloc(sizeof(struct Node)+10);
(moreover it is unclear what the magic number 10 means in this expression sizeof(struct Node)+10). And then if the condition of the if statement
if(checkDuplicates(nData)==1){
return;
evaluates to logical true the function exits without freeing the allocated memory.
You need at first to check whether the value is not already present in the list and only after that to allocate memory for the new node.
As for the reason of the error then it seems the reason of the error is inside the function delete. The function does not reset the pointer tail when a single node is present in the list or when the node pointed to by the pointer tail is removed.
And apart from this even the first statement of the function
if(head -> data==n){
can invoke undefined behavior when the function is called for an empty list.
The function should be defined the following way
int delete( int n )
{
struct Node *current = head;
struct Node *prev = NULL;
while ( current != NULL && current->data != n )
{
prev = current;
current = current->next;
}
int success = current != NULL;
if ( success )
{
if ( prev == NULL )
{
head = head->next;
if ( head == NULL ) tail = NULL;
}
else
{
prev->next = current->next;
if ( prev->next == NULL ) tail = prev;
}
free( current );
}
return success;
}
I created a program in c which :
Creates a simple linked list in c in which I store letters
Print the content of every node
delete the last node
Print the content of the list again
The problem is with the "delete_last" function because prints in terminal an infinite loop (I believe that the problem is invoked when I use free funtion.)
#include<stdio.h>
#include<stdlib.h>
typedef struct node {
char xar;
struct node *next;
}Node;
void insert_list(Node **head , int len)
{
char x;
Node **list;
Node *node1 , *node2;
node1=(Node*)malloc(sizeof(Node));
printf("Give 5 characters : ");
x=getchar();
node1->xar = x;
node1->next=NULL;
list=&node1;
int i=0;
for(i=1 ; i < len ; i++)
{ x=getchar();
node2 = (node*)malloc(sizeof(node));
node2->xar = x;
node2->next = NULL;
(*list) -> next = node2;
list = &(*list) -> next ;
}
*head=node1;
}
void print_list(Node *head)
{
Node**lpp;
for(lpp=&head ; *lpp!=NULL ; lpp=&(*lpp)->next)
{
printf("\n the chars are %c" , (*lpp)->xar);
}
}
void delete_last(Node *head)
{
Node **lpp;
lpp=&head;
while((*lpp)->next!=NULL)
{
lpp=&(*lpp)->next;
}
free(*lpp);
}
int main()
{
Node *kefali ;
kefali = NULL;
insert_list(&kefali , 5);
print_list(kefali);
printf("\n");
delete_last(kefali);
print_list(kefali);
return 0;
}
You mustn't access to freed objects.
In the delete_last functon, you called free() for one of the nodes, but you didn't update any pointers there. This will have the following call of print_list access a freed object, invoking undefined behavior.
You should add
*lpp = NULL;
after
free(*lpp);
To get the freed node out of the list.
Note that this won't work for removing the first (only) element in the list because the head is passed as a copy. You should change the function to accept a pointer to the head pointer to enable it remove the first element.
Your delete_last lacks a way of telling that the last element was deleted. Either pass a pointer to head or return a new head.
Further, it's way to complicated. Using lpp as pointer to pointer is not necessary - it only complicates the code. Keep it simple.
Here is an example which returns the new head.
Node* delete_last(Node *head)
{
if (head == NULL) return NULL; // empty list
if (head->next == NULL)
{
// Only one element...
free(head);
return NULL;
}
Node *prev = head;
Node *lpp = prev->next;
while (lpp->next)
{
prev = lpp;
lpp = prev->next;
}
prev->next = NULL;
free(lpp);
return head;
}
and call it like:
head = delete_last(head);
Here is an example which takes a pointer to head.
Node* delete_last(Node **head)
{
if (head == NULL) exit(1); // illegal call
if (*head == NULL) return NULL; // empty list
if ((*head)->next == NULL)
{
// Only one element...
free(*head);
*head = NULL;
return;
}
Node *prev = *head;
Node *lpp = prev->next;
while (lpp->next)
{
prev = lpp;
lpp = prev->next;
}
prev->next = NULL;
free(lpp);
}
and call it like:
delete_last(&head);
You do not update the previous node (you need to keep track on it when iterating)
This makes no sense as you take reference to the local variable head and it does not change the the head of list when last element is deleted.
Node **lpp;
lpp=&head;
To prevent double-pointer function returns the head. Assign it when called. If return value is NULL the last element was deleted
Node *delete_last(Node *head)
{
Node *lpp = NULL, *prev;
if(head)
{
lpp=head -> next;
prev = head;
while(lpp->next)
{
prev = lpp;
lpp = lpp -> next;
}
if(prev == head && lpp == NULL)
{
free(head);
head = NULL; //empty list
}
else
{
free(lpp);
prev -> next = NULL;
}
}
free(lpp);
return head;
}
You can also use double pointer to modify the head when needed:
void delete_last(Node **head)
{
Node *lpp = NULL;
if(head && *head)
{
if(!(*head) -> next)
{
free(*head);
*head = NULL;
}
else
{
lpp = *head;
while(lpp -> next -> next)
{
lpp = lpp -> next;
}
free(lpp -> next);
lpp -> next = NULL;
}
}
}
I don't understand why we have to return pointers to the head node after a node has been added to a linked list.
struct node *append(int v) {
struct node *ptr;
struct node *t;
ptr=head;
while (ptr->next != tail) ptr = ptr->next;
t=(struct node *) malloc(sizeof *t);
t->value=v;
t->next = tail;
ptr->next = t;
return ptr; // why return ptr?
}
It depends of the context of your problem. Usually in linked list problems you have to return the head of the list so you can have your data structure consistent, but I infer from your code that the head is a global variable.
Unless the code that are invoking this function needs to know the location of the new node created, you don't need to return the node since your head is a global variable (again, if my assumption is correct).
Besides this, I suggest to revise your function since I see some cases you are missing here (what if the list comes empty and you have to change the head for example?)
First of all the function is invalid. When the list is empty and the first element is added head can be equal to NULL. So using expression head->next that in the function code corresponds to ptr->next results in memory access violation.
Also in my opinion it is not a good idea to name NULL as tail. I would explicitly use NULL. Otherwise the code can confuse readers.
Neverteless the function can look the following way
struct node * append( int v )
{
struct node *t = ( struct node * )malloc( sizeof( *t ) );
t->value = v;
t->next = tail;
if ( head == tail )
{
head = t;
}
else
{
struct node *current = head;
while ( current->next != tail ) current = current->next;
current->next = t;
}
return t;
}
As for your question then I also do not understand why the function returns ptr instead of t. It should return t. In this case the function would be more correct and efficient because it would return head when the first element is appended to the empty list and when a next non-first value is appended to the list and the head would be some node (not necessary the head itself) the while loop had no iteration because the first expression ptr->next would be equal already to NULL.
The function should return the last appended node as in the implementation I have shown.
I am sure that it is simply an error in the design of the function.:)
This drawback will be more visible if do not use the global variable head within the function but declare it as a function parameter. For example
struct node * append( struct node *head, int v )
{
struct node *t = ( struct node * )malloc( sizeof( *t ) );
t->value = v;
t->next = tail;
if ( head == tail )
{
head = t;
}
else
{
struct node *current = head;
while ( current->next != tail ) current = current->next;
current->next = t;
}
return t;
}
In this case the function call in main could look for example the following way
struct node *head = NULL;
struct node *current;
int i;
head = append( head, 0 );
for ( i = 1, current = head; i < 10; i++ ) current = append( current, i );
In this case the call of append would be very efficient because within the function the while loop would not make even one iteration.
Linked lists are often implemented with a NULL head when the list is empty. In this case, you have to return the head of the list when the head is a local variable, or when it is a global and you want to have more than one list using the same function. When adding a node, the head may have changed, even if adding at tail, in the case the list was empty there is a new head.
But another way to do is to always have a node at the head, just here to indicate the head, and adding/reading/deleting nodes after this head in order to treat datas in the list. In this case, returning the head is useless, because the head never change.
You can detect the tail of the list when for a node n: n->next == NULL, using a head equal to NULL when the list is empty, as the following code do:
// add at the tail of the list:
struct node * add_to_list_tail(struct node * head,int v) {
struct node *t;
t=(struct node *) malloc(sizeof(struct node));
t->value = v;
t->next = NULL; // next is set to NULL because it is the new tail
if(head == NULL) {
// in the case the list is empty
head = t; // t become the new head, because the list was empty
} else {
// in the case the list isn't empty
struct node * n = head;
// the following loop will stop when n->next == NULL, and n will point to the tail
while(n->next != NULL) {
n = n->next;
}
n->next = t;
}
return head;
}
// add at the head of the list:
struct node * add_to_list(struct node * head,int v) {
struct node *t;
t=(struct node *) malloc(sizeof(struct node));
t->value = v;
t->next = head; // make t become the new head
return t; // return t because it is the new head
}
int main() {
struct node * head = NULL;
head = add_to_list(head,1);
head = add_to_list(head,2);
head = add_to_list_tail(head,3);
}
If you don't want to return the head, you can also pass a pointer to the head pointer, as parameter for the functions that manipulate the list. A short sample code:
void add_to_list(struct node ** head,int v) {
struct node *t;
t=(struct node *) malloc(sizeof(struct node));
t->value = v;
// make t become the new head:
t->next = *head;
*head = t;
}
int main() {
struct node * head = NULL;
// we pass &head, the adress of variable head, as parameter:
add_to_list(&head,1);
add_to_list(&head,2);
struct node * n = head;
while(n != NULL) {
printf("\nvalue: %d",n->value);
n = n->next;
}
}
I've implemented a Linked-List with a Pop function in C:
Node * pop (Node * head) {
Node * temp = head;
printf("Temp is: %s\n", temp->val);
if (head->next != NULL) {
*head = *head->next;
}
printf("Temp is: %s\n", temp->val);
return temp;
}
And the output when I pop would be something like:
Temp is: node1 value
Temp is: node2 value
That is to say that temp is becoming temp->next when I assign *head = *head->next.
So how can I get the value of the current head and return it while also moving the head of the Linked-list to head->next?
Doing head = head->next does NOT remove the reference to the first node. (i.e. When I print the list, the first node is still there).
First, note that your code (and some of the previous solutions) will never pop the last element off the list. You want
if (*head != NULL) ...
Next, passing a pointer to a pointer will work. But it's actually better to make a list header like this:
typedef struct node_s {
struct node_s *next;
... data declaration here
} Node;
typedef struct list_s {
struct node_s *head;
} List;
void init_list(List *list) {
list->head = NULL;
}
Now declare a list like this:
List list[1];
init_list(list);
Declaring an array of one element makes every reference to list a pointer automatically, which eliminates lots of &'s in your code. Then it's nice and clean to implement push and pop:
void push(List *list, Node *node) {
node->next = list->head;
list->head = node;
}
Node *pop(List *list) {
Node *head = list->head;
if (head) {
list->head = head->next;
head->next = NULL;
}
return head;
}
Why is this better? Say you decide later to keep a count of items in the list. With the separate header node this is very easy:
typedef struct list_s {
struct node_s *head;
int length;
} List;
void init_list(List *list) {
list->head = NULL;
length = 0;
}
void push(List *list, Node *node) {
node->next = list->head;
list->head = node;
++list->length;
}
Node *pop(List *list) {
Node *head = list->head;
if (head) {
list->head = head->next;
head->next = NULL;
--list->length;
}
return head;
}
Note no calling code needs to change. With the pointer to pointer approach you are at a dead end. There are many other use cases where having a separate list header makes your code more flexible for future changes.
Your need to pass the address of head for your function to modify it. Then your function needs to dereference this address. Further, the last pop() needs to change *AddressOfHead as well
Node *pop(Node **AddressOfHead) {
Node *temp = *AddressOfHead;
if (temp) {
*AddressOfHead = temp->next;
}
return temp;
}
...
// Usage example
Node *TopOfList = pop(&Head);
Others have told you how to fix it, let me answer why temp changed..
Node * pop (Node * head) {
You are passing head as a pointer to a Node.
Thus when you do
*head = *head->next;
I think it is parsed as
*head = *(head->next);
And thus COPIES the object that is in next into the object at head, which is ofcourse the same object at temp.
Pointers are passed by value. That is, when you pass a pointer to the stack, a change in the called function to what the pointer points to is not reflected in the calling function.
In order for the value of the node pointer to be changed in the calling function, you need to pass the stack as a pointer to a pointer:
Node* pop (Node** head) {
Node* temp = *head;
if (temp) {
*head = temp->next; // to update stack in calling function
temp->next = NULL; // to detach temp from the rest of the list
}
return temp;
}
You do not need to check if ((*head)->next) or in this case if (temp->next) before updating the value of *head, because if you are at the last node of the stack and the next node is NULL, you want the list to be NULL anyway.
Karthik T's answer has the right explanation for why the value of temp was changing in your original code.
void pop(struct node** tol) {
struct node* t = *tol;
while (t->link->link != NULL){
t = t->link;
}
t->link = NULL;
}