I am trying to write a recursive function to reverse a doubly linked list. This code is not complete yet but I am hit with a issue. The application is not executing completely.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef struct nodes
{
uint8_t x;
struct nodes *next;
struct nodes *prev;
}Node;
Node *head = NULL;
void rev_rec_dll(Node **a, Node **b)
{
//check if it is last node in the list
if((*a)->next != NULL)
{
//set next to prev and prev to next
(*a)->next = (*a)->prev;
(*a)->prev = (*b);
printf("done for node %d and moving on..\n", ((*a)->x));
//recursive call by passing next two nodes
rev_rec_dll(b, &((*b)->next));
}
else
{
printf("reached new head\r\n");
head = (*a);
}
}
void add_node(Node **h_node, uint8_t x)
{
//check if there is at least one node in the list and if not add first node
if((*h_node) == NULL)
{
*h_node = (Node *)malloc(sizeof(Node));
(*h_node)->x = x;
(*h_node)->next = NULL;
(*h_node)->prev = NULL;
}
else
{
Node *temp = *h_node;
//get the last node
while(temp->next != NULL)
{
temp = temp->next;
}
//add new node
Node *newNode = (Node *)malloc(sizeof(Node));
newNode->x = x;
newNode->next = NULL;
newNode->prev = temp;
temp->next = newNode;
}
}
void display_nodes(Node *h_node)
{
while(h_node != NULL)
{
printf("Node: %u\n", h_node->x);
h_node = h_node->next;
}
}
int main(int argc, char **argv)
{
//add three nodes
add_node(&head, 1);
add_node(&head, 2);
add_node(&head, 3);
//display nodes
display_nodes(head);
//add three more nodes
add_node(&head, 4);
add_node(&head, 5);
add_node(&head, 6);
//display all 6 nodes
display_nodes(head);
//reverse the linked list
rev_rec_dll(&head, &(head->next));
//display reversed nodes
display_nodes(head);
return 0;
}
The output of the program is given below:
Node: 1
Node: 2
Node: 3
Node: 1
Node: 2
Node: 3
Node: 4
Node: 5
Node: 6
done for node 1 and moving on..
I want to know what is wrong in the function rev_rec_dll(). Also, I want to know if the way I am passing the arguments to this function is correct or not. If it is not correct please provide appropriate reason on why it is wrong. The arguments passed to rev_rec_dll function is current node and next node in the linked list.
The reversing logic may not be accurate but I want to know if the way the arguments are passed is correct. Why does it exit in the middle? A memory violation?
For starters it is a bad idea to declare the pointer to head node as a file scope variable and when the functions depend on the file scope variable.
Node *head = NULL;
You should move this declaration inside the function main and correspondingly rewrite your functions.
Also the structure declaration will look better if to declare it like
typedef struct Node
{
uint8_t x;
struct Node *next;
struct Node *prev;
} Node;
Otherwise the names nodes and Node will only confuse readers of the code.
There are two problems with the function. The first one is that initially the second function argument points to the data member next of the head node
rev_rec_dll(&head, &(head->next));
that is changed within the function in the compound statement of the if statement.
To make it clear consider a list that contains only two nodes
| NULL <- 1 -> 2 | <-> | 1 <- 2 -> NULL|
Inside the first recursive call of the function there are executed the following statements
(*a)->next = (*a)->prev;
(*a)->prev = (*b);
Again pay attention to that the function is called like
rev_rec_dll(&head, &(head->next));
That is the parameter b of the function points to the data member next of the head node and the first of the above statements changes the value of the data member
(*a)->next = (*a)->prev;
So now the expression *b yields data member next that now contains the value of the data member prev (in this case NULL).
In fact you have
(*a)->next = (*a)->prev;
(*a)->prev = ( *a )->next; //(*b);
because the expressions ( *a )->next and *b are equivalent due to initializations of parameters by argument expressions.
That is the both data members. next and prev, get the initial value of the data member prev and you have
| NULL <- 1 -> NULL | <- | 1 <- 2 -> NULL|
Then the function is called like
rev_rec_dll(b, &((*b)->next));
that invokes undefined behavior because the expression *b yields a null pointer.
Another problem is that in this code snippet
else
{
printf("reached new head\r\n");
head = (*a);
}
data members prev and next of the last node in the list are not changed because the control is bypassed the compound statement of the if statement
And moreover your function will invoke undefined behavior if it will
be called for an empty list.
The function should be declared with only one parameter like for example
void rev_rec_dll( Node **head );
Here is a demonstration program that shows how the recursive function that reverses the list can be implemented.
In the demonstration program there is not used a file scope pointer to the head node. In this case within a program you will be able to define multiple lists.
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <inttypes.h>
typedef struct Node
{
uint8_t x;
struct Node *next;
struct Node *prev;
} Node;
void clear( Node **head )
{
while (*head)
{
Node *current = *head;
*head = ( *head )->next;
free( current );
}
}
size_t assign( Node **head, const uint8_t *a, size_t n )
{
clear( head );
size_t cnt = 0;
for ( Node *prev = NULL; n-- && ( *head = malloc( sizeof( Node ) ) ) != NULL; cnt++)
{
( *head )->x = *a++;
( *head )->next = NULL;
( *head )->prev = prev;
prev = *head;
head = &( *head )->next;
}
return cnt;
}
void rev_rec_dll( Node **head )
{
if ( *head )
{
Node *tmp = ( *head )->next;
( *head )->next = ( *head )->prev;
( *head )->prev = tmp;
if (( *head )->prev != NULL)
{
*head = ( *head )->prev;
rev_rec_dll( head );
}
}
}
void display_nodes( const Node *head )
{
for (; head != NULL; head = head->next)
{
printf( "%" PRIu8 " -> ", head->x );
}
puts( "null" );
}
int main( void )
{
Node *head = NULL;
uint8_t a[] = { 1, 2, 3, 4, 5, 6 };
assign( &head, a, sizeof( a ) / sizeof( *a ) );
display_nodes( head );
rev_rec_dll( &head );
display_nodes( head );
clear( &head );
}
The program output is
1 -> 2 -> 3 -> 4 -> 5 -> 6 -> null
6 -> 5 -> 4 -> 3 -> 2 -> 1 -> null
There's no real point of using pointer to a pointer in rev_rec_dll(Node **a, Node **b), i would suggest you read into practical implications of pointers to pointers
What you can do here is just use regular pointers like so:
void rev_rec_dll(Node* a, Node* b)
{
//check if it is last node in the list
if(a->next != NULL)
{
//set next to prev and prev to next
a->next = a->prev;
a->prev = b;
printf("done for node %d and moving on..\n", a->x);
//recursive call by passing next two nodes
rev_rec_dll(b, b->next);
}
else
{
printf("reached new head\r\n");
head = a;
}
}
then in main function call it like so
rev_rec_dll(head, head->next);
also, as Vlad mentioned you shouldn't use two parameters in this function, it adds unnecessary complexity as well as makes it a bit harder to track if you pass and use NULL in the future.
also also, it's best that you learn how to use debugger now to see where things hit the fan clearly.
Related
having segmentation error while trying to access nodes
i can create new nodes with my add function after function executes i cant access my nodes. i think they deallocated in memory but i couldnt figure it out.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *nextNode;
};
struct node *head;
void add(int data)
{
struct node *new = (struct node *)malloc(sizeof(struct node));
new->data = data;
new->nextNode = NULL;
struct node *temp1;
temp1 = head;
while (temp1 != NULL)
{
temp1 = temp1->nextNode;
}
temp1 = new;
printf("\nValue of temp1:%d\nValue of new: %d\n",temp1,new);
printf("\nData of temp1:%d\nData of new:%d\n",temp1->data,new->data);
}
void printList()
{
int i = 1;
struct node *tempP;
tempP = head;
while (tempP != NULL)
{
printf("\nData of %dth element is : %d\n", i, tempP->data);
tempP = tempP->nextNode;
i++;
}
}
void main()
{
head = (struct node *)malloc(sizeof(struct node));
head->data = 10;
head->nextNode = NULL;
add(20);
add(30);
add(40);
printList();
}
This code snippet within the function add
struct node *temp1;
temp1 = head;
while (temp1 != NULL)
{
temp1 = temp1->nextNode;
}
temp1 = new;
is wrong. Within it there is changed the local variable temp1. It is not linked with the list.
Also using the conversion specifier %d to output a pointer invokes undefined behavior. You should use conversion specifier %p.
Using your approach to the function definition you could write instead.
void add(int data)
{
struct node *new = malloc( sizeof( *new ) );
new->data = data;
new->nextNode = NULL;
if ( head == NULL )
{
head = new;
}
else
{
struct node *temp1 = head;
while ( temp1->nextNode != NULL)
{
temp1 = temp1->nextNode;
}
temp1->nextNode = new;
}
printf("\nValue of temp1->nextNode:%p\nValue of new: %p\n",
( void * )temp1->nextNode, ( void * )new);
printf("\nData of temp1->nectNode:%d\nData of new:%d\n",
temp1->nextNode->data,new->data);
}
Pay attention to that it is a bad design when functions depend on a global variable as in your case where the functions depend on the global variable head.
And it is also a bad idea when the first node is added to the list bypassing the function add.
And you need check whether a node was successfully allocated.
Also according to the C Standard the function main without parameters shall be declared like
int main( void )
As for me I would declare the pointer to the head node in main like
int main( void )
{
struct node *head = NULL;
// ...
And the function add will look like
int add( struct node **head, int data )
{
struct node *new_node = malloc( sizeof( *new_node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = data;
new_node->nextNode = NULL;
while ( *head != NULL ) head = &( *head )->nextNode;
*head = new_node;
}
return success;
}
and called like
struct node *head = NULL;
add( &head, 10 );
add( &head, 20 );
add( &head, 30 );
add( &head, 40 );
In turn the function printList can look like
void printList( const struct node *head )
{
for ( size_t i = 1; head != NULL; head = head->nextNode )
{
printf( "Data of %zuth element is : %d\n", i++, head->data);
}
}
And you need at least to write one more function that will free all the allocated memory.
There were a handful of mistakes in your add() function, which I've highlighted and fixed below:
void add(int data)
{
struct node *new = malloc(sizeof(*new)); // suggested by ryyker
new->data = data;
new->nextNode = NULL;
struct node *temp1 = head; // just keep it short
while (temp1->nextNode != NULL) // temp1 != NULL will always result in it being NULL, last node is the node with NULL as next
{
temp1 = temp1->nextNode;
}
temp1->nextNode = new; // you want the next in the list to be the new node, not reassign the head to a new node. That's a memory leak.
// remember: temp1 == head, and head = new makes head lose the original node and point to the newly created one
printf("\nValue of temp1:%p\nValue of new: %p\n",temp1,new); // %p for pointers
printf("\nData of temp1:%d\nData of new:%d\n",temp1->data,new->data);
}
Output:
Value of temp1:0x55809a4b22a0
Value of new: 0x55809a4b22c0
Data of temp1:10
Data of new:20
Value of temp1:0x55809a4b22c0
Value of new: 0x55809a4b26f0
Data of temp1:20
Data of new:30
Value of temp1:0x55809a4b26f0
Value of new: 0x55809a4b2710
Data of temp1:30
Data of new:40
Data of 1th element is : 10
Data of 2th element is : 20
Data of 3th element is : 30
Data of 4th element is : 40
I was trying to reverse a linked list but I kept comming across an issue. I finally figured out was wrong and fixed it, however I do not understand why my last approach doesn't work. The code below is the one that successfully reverses a linked list.
void reverse_list(list** head)
{
list* currNode = *head;
list* prevNode = NULL;
list* tmpNode;
while(1)
{
tmpNode = currNode->next;
currNode->next = prevNode;
if(tmpNode == NULL)
{
*head = currNode;
break;
}
prevNode = currNode;
currNode = tmpNode;
}
}
However, the code below does not work. Both use double pointers, but in this one I dereferenced head twice to get to the actual object and assigned it with *currNode. When I run this code, It ends up going into an infinite loop and its missing the last item. For example, if the items were 1,2,3,4,5, then the reverse would be 5,4,3,2, and it keeps printing the same list. I don't understand why this approach isn't working since I'm accessing the actual object (by derefrening twice) and assigning it with a new object (*currNode).
void reverse_list(list** head)
{
list* currNode = *head;
list* prevNode = NULL;
list* tmpNode;
while(1)
{
tmpNode = currNode->next;
currNode->next = prevNode;
if(tmpNode == NULL)
{
**head = *currNode;
break;
}
prevNode = currNode;
currNode = tmpNode;
}
}
The code below has the same issue as the one above. I followed the same approach as with the above code only this one uses a single pointer.
void reverse_list(list* head)
{
list* currNode = head;
list* prevNode = NULL;
list* tmpNode;
while(1)
{
tmpNode = currNode->next;
currNode->next = prevNode;
if(tmpNode == NULL)
{
*head = *currNode;
break;
}
prevNode = currNode;
currNode = tmpNode;
}
}
Any help to understand this would greatly be appreciated. Thank you!
Different levels of indirection.
Given list** head, *head is the value pointed to by head, a pointer to a Node, a list *. We dereference one more time and **head dereferences to list * and then to list. We're all out of pointers and and are accessing the object at the end of the line. So
**head = *currNode;
dereferences both pointers all the way back to the objects. This is assigning values to objects, not addresses to pointers to objects. Rather than changing the linkage of the list by updating pointers, whatever list head ultimately pointed at has been changed to match currNode, breaking the integrity of the list.
*head = currNode;
only derefences head one level closer to the object. Here we are operating on pointers and changing linkage.
In the final example we have
*head = *currNode;
and this is similar to the first failed attempt. It is assigning values rather than changing the pointers.
For starters all the three functions in general can invoke undefined behavior when they are called for empty lists due to these lines
list* currNode = head;
//...
tmpNode = currNode->next;
because there is used a null pointer to access memory.
In the second function in this if statement
if(tmpNode == NULL)
{
**head = *currNode;
break;
}
the original first node is overwritten by the last node
**head = *currNode;
So after exiting the function you will have that the original pointer head still points to the originally first node that was overwritten by the last node of the list. So as a result one actual data will be lost and there will be a memory leak.
As for the third function then it is enough to point to that the function accepts the pointer to the head node by value.
void reverse_list(list* head)
That is the function deals with a copy of the value of the original variable head. Changing the copy will not influence on the original pointer. The original pointer will still point to the first node.
The function can look simpler the following way
void reverse( list **head )
{
list *current = *head;
*head = NULL;
while ( current != NULL )
{
struct Node *tmp = current;
current = current->next;
tmp->next = *head;
*head = tmp;
}
}
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
typedef struct Node
{
int data;
struct Node *next;
} list;
int push_front( list **head, int data )
{
list *new_node = malloc( sizeof( list ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = data;
new_node->next = *head;
*head = new_node;
}
return success;
}
void display( const list *head )
{
for ( ; head != NULL; head = head->next )
{
printf( "%d -> ", head->data );
}
puts( "null" );
}
void reverse( list **head )
{
list *current = *head;
*head = NULL;
while ( current != NULL )
{
list *tmp = current;
current = current->next;
tmp->next = *head;
*head = tmp;
}
}
int main(void)
{
const int N = 10;
list *head = NULL;
display( head );
reverse( &head );
display( head );
putchar( '\n' );
for ( int i = 0; i < N; i++ )
{
push_front( &head, i );
}
display( head );
reverse( &head );
display( head );
return 0;
}
The program output is
null
null
9 -> 8 -> 7 -> 6 -> 5 -> 4 -> 3 -> 2 -> 1 -> 0 -> null
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 2 years ago.
Improve this question
I'm writing a program that creates a doubly linked list and removes a element with negative value from it. Everything pretty much works, except for the part when I called the modify function and when I try to delete it, program crashes. Any suggestions?
/*
*Given a doubly linked lists with +ve and -ve key values.
*Write a function to delete all the nodes with negative key values.
*/
#include<stdio.h>
#include<stdlib.h>
struct list {
int data;
struct list *next;
struct list *prev;
};
struct list *head = NULL;
struct list* create(int);
void modify(struct list*);
int main(void) {
int n, i, value;
struct list *temp;
printf("Enter the count of node :");
scanf("%d",&n);
for (i = 0; i < n; i ++) {
printf("Enter the value of node: ");
scanf("%d",&value);
create(value);
}
temp = head;
printf("\nDoubly linked list is created and the list is as follows : \n");
while (temp != NULL) {
printf("%d ",temp -> data);
temp = temp -> next;
}
modify(head);
}
struct list* create(int value) {
struct list *new_node, *temp;
temp = head;
new_node = (struct list*)malloc(sizeof(struct list));
new_node -> data = value;
new_node -> next = NULL;
new_node -> prev = NULL;
if (head == NULL) {
head = new_node;
}
else {
while (temp -> next != NULL) {
temp = temp -> next;
}
temp -> next = new_node;
new_node -> prev = temp;
}
return head;
}
void modify(struct list *head) {
struct list *current_node, *prev_node, *next_node, *temp;
temp = head;
while (temp -> next != NULL) {
if (temp -> data < 0) {
current_node = temp;
prev_node = temp -> prev;
next_node = temp -> next;
prev_node -> next = next_node;
next_node -> prev = prev_node;
free(current_node);
}
}
printf("\nThe modified doubly linked list is : \n ");
temp = head;
while (temp -> next != NULL) {
printf("%d",temp -> data);
temp = temp -> next;
}
}
See the examples of Vlad from Moscow to have a better understanding of what you were doing.
I shall go trough your code and tell you what I would change.
/*
*Given a doubly linked lists with +ve and -ve key values.
*Write a function to delete all the nodes with negative key values.
*/
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
First of all: you're making a (doubly linked) list of nodes, not a list of lists. Call it a Node. Also, you can do a typedef to prevent you from writing struct Node all the time.
struct Node {
int data;
struct Node* next;
struct Node* prev;
};
void append(struct Node** head, int value); // variable names aren't needed here
struct Node* findLastNode(struct Node** head);
void removeNegativeNodes(struct Node** head);
void removeNode(struct Node** head, struct Node* currNode);
int main(void)
{
Try not to use global variables. There are many reasons to be found why not to use them, but in here it's possible to don't use them as well. Imagine having thousands of lines of code, you won't be able to have a decent view on the code.
struct Node* head = NULL;
struct Node* p; // temp-<p>ointer
int n, value;
printf("Enter the count of node :");
scanf("%d", &n);
You only need i in the for-loop, so keep it there.
for (int i = 0; i < n; ++i) {
printf("Enter the value of node: ");
scanf("%d", &value);
Make sure your function names are clear and tell you what they do. create() would tell me it creates a Node, but not that it also appends the node.
append(&head, value);
}
// this can be in a function! (A) printData
p = head; // temp-<p>ointer
printf("\nDoubly linked list is created and the list is as follows : \n");
while (p != NULL) {
printf("%d <=> ", p->data);
p = p->next;
}
printf("NULL\n");
Look at what you're doing: perhaps you want to make a general function to split the code? Here you're again going trough the list and printing out it's data members.
// this can be in a function! (B) printData
removeNegativeNodes(&head);
printf("\nThe modified doubly linked list is : \n");
p = head;
while (p != NULL) {
printf("%d <=> ", p->data);
p = p->next;
}
printf("NULL\n");
}
struct Node* findLastNode(struct Node** head)
{
struct Node* p = *head;
if (p != NULL)
while (p->next != NULL)
p = p->next;
return p;
}
Since your head has to be changed, you'll have to pass the address of the head as well. Also, split your code a bit, so it's easier for yourself to have an idea of your code's structure. If your function is 40 rules long, it will take longer to find out where the cause of the bug is located (exactly).
void append(struct Node** head, int value)
{
struct Node* lastNode = findLastNode(head);
struct Node* nextNode = (struct Node*)malloc(sizeof(struct Node));
if (lastNode != NULL) {
lastNode->next = nextNode;
nextNode->prev = lastNode;
}
else {
*head = nextNode;
nextNode->prev = NULL;
}
nextNode->next = NULL;
nextNode->data = value;
}
Here as well: the first number can be negative, so make sure you can access the head variable by it's address. Also, again keep it simple and split your code in functions removeNegativeNodes > removeNode.
void removeNegativeNodes(struct Node** head)
{
struct Node* p = *head;
struct Node* temp;
while (p != NULL) {
temp = p->next;
if (p->data < 0)
removeNode(head, p);
p = temp;
}
}
void removeNode(struct Node** head, struct Node* currNode)
{
if (currNode->next != NULL)
currNode->next->prev = currNode->prev;
if (currNode->prev != NULL)
currNode->prev->next = currNode->next;
else
*head = currNode->next;
free(currNode);
}
I've tested the code and it should work. Having it worked properly is not important though, it's understanding what happens. I recommend you having a closer look to it. Goodluck!
Your definition of a doubly-linked list does not make great sense.
The list should contain two pointers: to the head node and to the tail node of the list.
So you need to define two structures. The first one defines the node and the second one defines the list itself.
In this case you need not to traverse the whole list to append a new node to the tail of the list.
The function create with the confusing name is based on the global variable head while the function modify instead gets the variable through a parameter.
This is very confusing. As result for example you can not create two lists in a program.
So as the function modify gets the pointer to the head node by value then it means that it deals with a copy of the pointer to the head node. As a result any changes of the pointer to the head node in the function does not influence on the original pointer to the head node.
This loop in the function modify
temp = head;
while (temp -> next != NULL) {
in general can invoke undefined behavior because it is not excluded that the pointer to the head node can be equal to NULL.
And in any case the condition of the loop does not make sense because within the loop you are considering not the next node but the current
while (temp -> next != NULL) {
if (temp -> data < 0) {
So a question arises if temp->next is equal to NULL but the value of the current node pointed to by the pointer temp is negative does it mean that this node will not be removed?
Pay attention to that if you will write the condition of the loop correctly nevertheless either data member prev of the removed node or the data member next of the removed node or even the both can be equal to NULL. In this case these statements
prev_node = temp -> prev;
next_node = temp -> next;
prev_node -> next = next_node;
^^^^^^^^^^^^^^^^^
next_node -> prev = prev_node;
^^^^^^^^^^^^^^^^^
again can invoke undefined behavior.
here is a demonstrative program that shows how the list and its functions can be defined. Investigate it.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
struct Node
{
int data;
struct Node *next;
struct Node *prev;
};
struct List
{
struct Node *head;
struct Node *tail;
};
int push_back( struct List *list, int data )
{
struct Node *new_node = malloc( sizeof( struct Node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = data;
new_node->next = NULL;
if ( list->head == NULL )
{
new_node->prev = NULL;
list->head = list->tail = new_node;
}
else
{
new_node->prev = list->tail;
list->tail = list->tail->next = new_node;
}
}
return success;
}
void remove_if( struct List *list, int predicate( int ) )
{
struct Node *prev = NULL;
for ( struct Node **current = &list->head; *current != NULL; )
{
if ( predicate( ( *current )->data ) )
{
struct Node *tmp = *current;
if ( ( *current )->next != NULL )
{
( *current )->next->prev = ( *current )->prev;
}
*current = ( *current )->next;
free( tmp );
}
else
{
prev = *current;
current = &( *current )->next;
}
}
list->tail = prev;
}
void display( const struct List *list )
{
for ( const struct Node *current = list->head; current != NULL; current = current->next )
{
printf( "%d -> ", current->data );
}
puts( "null" );
}
void display_reverse( const struct List *list )
{
for ( const struct Node *current = list->tail; current != NULL; current = current->prev )
{
printf( "%d -> ", current->data );
}
puts( "null" );
}
int is_negative( int data )
{
return data < 0;
}
int main(void)
{
struct List list = { .head = NULL, .tail = NULL };
const size_t N = 10;
srand( ( unsigned int )time( NULL ) );
for ( size_t i = 0; i < N; i++ )
{
push_back( &list, rand() % N - N / 2 );
}
display( &list );
display_reverse( &list );
putchar( '\n' );
remove_if( &list, is_negative );
display( &list );
display_reverse( &list );
putchar( '\n' );
return 0;
}
The program output might look like
2 -> 4 -> 3 -> -5 -> 3 -> -3 -> -3 -> -2 -> 0 -> 2 -> null
2 -> 0 -> -2 -> -3 -> -3 -> 3 -> -5 -> 3 -> 4 -> 2 -> null
2 -> 4 -> 3 -> 3 -> 0 -> 2 -> null
2 -> 0 -> 3 -> 3 -> 4 -> 2 -> null
The create() function returns a linked list item. so you have to assign the return value to an item. Also the definition of pointers inside the struct is completely wrong.
struct list {
int data;
struct list *next;
struct list *prev;
};
struct list *head = NULL;
struct list* create(int); //function prototype
void modify(struct list*);//function prototype
int main(void) {
int n, i, value;
struct list *temp;
printf("Enter the number of nodes :");
scanf("%d",&n);
for (i = 0; i < n; i ++) {
printf("Enter the value of node: ");
scanf("%d",&value);
create(value);
}
temp = head;
printf("\nDoubly linked list is created and the list is as follows : \n");
while (temp != NULL) {
printf("%d ",temp -> data);
temp = temp -> next;
}
modify(head);
}
void create(int value) {
struct list* point = head;
while(point->next){
if(point->data != value)
point = point->next;
else{
printf("Data exists\n");
return NULL;
}
}
struct list* item = (struct list*)malloc(sizeof(struct list));
item->data = value;
item->next = NULL;
item->prev = point;
}
void modify(struct list *head) {
struct list *current_node, *prev_node, *next_node, *temp;
temp = head;
while (temp -> next != NULL) {
if (temp -> data < 0) {
temp->prev->next = temp->next;
temp->next->prev = temp->prev;
free(temp);
}
temp = temp->next;
}
printf("\nThe modified doubly linked list is : \n ");
temp = head;
while (temp -> next != NULL) {
printf("%d",temp -> data);
temp = temp -> next;
}
}
I hope this will work for you.
I am practicing linked list structure while learning pointers and I have problem with appending item in list. Here is my code
#include <stdio.h>
#include <stdlib.h>
typedef struct node node_t;
struct node {
int data;
node_t* next;
};
void append(node_t *head, int data) {
if (head == NULL) {
node_t *node = (node_t*)malloc(sizeof(node_t*));
node->data = data;
node->next = NULL;
head = node;
} else {
node_t *node = (node_t*)malloc(sizeof(node_t*));
node->data = data;
node->next = NULL;
if (head->next == NULL) {
head->next = node;
} else {
node_t *current = head;
while (1) {
if (current->next == NULL) {
current->next = node;
break;
}
current = current->next;
}
}
}
}
int main(void) {
node_t *head = NULL;
append(head, 4);
append(head, 6);
printList(head);
return 0;
}
My code breaks when I do head = node; It doesn't change value of head in main. I think I'm missing something but not sure what.
Thank you in advance
You are passing the pointer head by value in the function append. So the function deals with a copy of the passed to it pointer. Changing the copy does not influence on the original pointer. Either pass it by reference or return updated head from the function.
The first approach is much better.
The function can look the following way
int append( node_t **head, int data )
{
node_t *node = malloc( sizeof( node_t ) );
int success = node != NULL;
if ( success )
{
node->data = data;
node->next = NULL;
while ( *head != NULL ) head = &( *head )->next;
*head = node;
}
return success;
}
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
typedef struct node node_t;
struct node
{
int data;
node_t *next;
};
int append( node_t **head, int data )
{
node_t *node = malloc( sizeof( node_t ) );
int success = node != NULL;
if ( success )
{
node->data = data;
node->next = NULL;
while ( *head != NULL ) head = &( *head )->next;
*head = node;
}
return success;
}
void printList( node_t *head )
{
for ( ; head != NULL; head = head->next )
{
printf( "%d -> ", head->data );
}
puts( "null" );
}
int main(void)
{
node_t *head = NULL;
const int N = 10;
for ( int i = 0; i < N; i++ )
{
append( &head, i );
}
printList( head );
return 0;
}
Its output is
0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> null
It seems the problem is you are passing the head pointer by value, so when you change it inside append(), you're only changing a local variable in that function - as opposed to the head variable within main().
This may be a bit confusing - if you pass a pointer, how can you be passing by value? Well, you might want to have a look at this question:
Is passing pointer argument, pass by value in C++?
... and the bottom line is that append() needs to take a node_t** head, and you'll call it from main with append(&head, 4);. See it working on Coliru.
Also you're allocating sizeof(node_t*) per node. You should be allocating sizeof(node_t).
It doesn't change value of head in main
Nor should it! If the value of head in main changed when you call append(), then your call to printList() would only print the last node in the list, and you'd have no way to refer to the other nodes in the list.
The reason that head isn't changed has been well explained in other answers, i.e. you're passing the head pointer by value. It's important to understand that the head in main() and the head parameter in append() are entirely different variables.
You pass the head of the list by value, so the append function cannot update the pointer in the caller's space, that happens to have the same name head. The head argument in append is a separate variable from the head local variable in main.
You should either pass a pointer to the head node so append can modify it:
void append(node_t **headp, int data) { ...
Or return the possibly modified head node to the caller which will store it back to its own variable:
node_t *append(node_t *head, int data) { ...
In both cases, it is advisable to signal memory allocation failure to the caller. Returning an error code in the first approach is easy, while returning a null pointer in the second approach can work, as long as the caller does not store the return value directly into its head variable, as in case of failure the previous value would be lost.
Here is a modified version with the first approach:
#include <stdio.h>
#include <stdlib.h>
typedef struct node node_t;
struct node {
int data;
node_t *next;
};
// append a new node to the list, return 0 for success, -1 for allocation failure
int append(node_t **headp, int data) {
node_t *node = (node_t *)malloc(sizeof(node_t *));
if (node == NULL)
return -1;
node->data = data;
node->next = NULL;
if (*headp == NULL) {
*headp = node;
} else {
node_t *current = *headp;
while (current->next != NULL) {
current = current->next;
}
current->next = node;
}
return 0;
}
int main(void) {
node_t *head = NULL;
if (append(&head, 4) || append(&head, 6))
printf("node allocation error\n");
printList(head);
// should free the list
return 0;
}
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;
}
}