Reverse a linked list in c - c

void reverse(node *pointer) {
node *head, *curr;
head = pointer;
curr = head;
while (head != NULL) {
while (curr -> next != NULL) {
curr = curr -> next;
}
printf("%d", curr -> data);
free(curr);
curr = head;
}
}
I don't know what's wrong with the code it prints only the last node of the linked list while trying to reverse it.

Simply:
node *reverse(node *head){
node *result = NULL;
while (head) {
node *next = head->next;
head->next = result;
result = head;
head = next;
}
return result;
}

You will not be able to see the output of the above function mainly for two reasons
Passing by value instead of reference.
No print statement inside the function. The effect of this function will be destroyed as soon as it comes out of the function.
In code:
void reverse(struct node** head_ref) {
struct node* prev = NULL;
struct node* current = *head_ref;
struct node* next;
while (current != NULL) {
next = current->next;
current->next = prev;
prev = current;
current = next;
}
*head_ref = prev;
}

Related

I cannot print delete_first result in C (circular linkedlist)

I want to print delete_first result and delete_last result. But it can only print delete_last code. How can i solve this matter?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
typedef int element;
typedef struct ListNode {
element data;
struct ListNode* link;
} ListNode;
void print_list(ListNode* head)
{
ListNode* p;
if (head == NULL) return;
else {
p = head->link;
do {
printf("%d ", p->data);
p = p->link;
} while (p != head->link);
}printf("\n");
}
ListNode* insert_first(ListNode* head, element data)
{
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
node->data = data;
if (head == NULL) {
head = node;
node->link = head;
}
else {
node->link = head->link;
head->link = node;
}
return head;
}
ListNode* insert_last(ListNode* head, element data)
{
ListNode* node = (ListNode*)malloc(sizeof(ListNode));
node->data = data;
if (head == NULL) {
head = node;
node->link = head;
}
else {
node->link = head->link;
head->link = node;
head = node;
}
return head;
}
I want to print delete_first result and delete_last result. But I can only print delete_last result. How can i print delete_first result?
This is my delete_first code.
ListNode* delete_first(ListNode* head) {
if (head == NULL)
{
return head;
}
if (head->link == head) {
free(head);
head = NULL;
return head;
}
ListNode* p = head->link;
head->link = p->link;
free(head);
head = NULL;
return head;
}
ListNode* delete_last(ListNode* head) {
if (head == NULL)
return head;
ListNode* p = head->link;
if (head->link == head) {
free(head);
head = NULL;
return head;
}
while (p->link != head) {
p = p->link;
}
p->link = head->link;
free(head);
head = p;
return head;
}
int main() {
ListNode* head = NULL;
head = insert_first(head, 10);
head = insert_first(head, 20);
head = insert_first(head, 30);
head = insert_first(head, 40);
head = insert_last(head, 50);
print_list(head);
head=delete_last(head);
print_list(head);
head = delete_first(head);
print_list(head);
return 0;
}
If you want to print the element being removed, then you cannot free() it, or you have to copy it to a local variable and return it by value.
If you want caller to be able to print what remains of the list, then you need to find the last node which has a link that points at head and have it point at head->next instead. Then return that value (instead of NULL):
ListNode* delete_first(ListNode* head) {
if(!head)
return NULL;
if(head == head->link) {
free(head);
return NULL;
}
ListNode* last;
for(last = head; last->link != head; last = last->link);
last->link = head->link;
free(head);
return last->link;
}
There is no point of setting head = NULL as the copy of that variable is lost the caller anyways.

Segment Fault - Linked List in C

I am creating a basic linked list in C but I am getting a segment fault when my add to back function is called in my test file. It seems to have a problem because the head of the list is NULL, but I don't see why this is an issue. When I use the cgdb tool, it tells me the error is occurring on the line: prev->next = new_node. I have attached the full code below, please let me know what I am not seeing to fix this.
header file
#ifndef LINKED_LIST_H
#define LINKED_LIST_H
typedef struct Node {
int data;
struct Node *next;
} Node;
Node *create_node(int data);
void free_list(Node *head);
void add_to_front(struct Node **head, int data);
void print_list(struct Node *head);
void reverse_list(struct Node **head);
void add_to_back(Node **head, int data);
#endif // LINKED_LIST_H
.c file
#include <stdio.h>
#include <stdlib.h>
#include "linked_list.h"
/* returns a new node whose data is set to DATA and next is set to NULL */
Node *create_node(int data) {
struct Node *new_node = malloc(sizeof(struct Node));
if (new_node == NULL) {
perror("Malloc failed\n");
}
new_node->data = data;
new_node->next = NULL;
return new_node;
}
/* Frees the list starting at HEAD */
void free_list(Node *head) {
while (head != NULL) {
Node *temp = head->next;
free(head);
head = temp;
}
}
/* Creates a new node whose data is set to DATA and adds it to the front of the
list pointed to by HEAD.
*/
void add_to_front(struct Node **head, int data) {
/* Check if the head is NULL to make sure that we do not dereference a NULL pointer
because that would result in a segfault */
if (head == NULL) return;
struct Node *new_node = create_node(data);
if (*head != NULL) {
/* The list is not empty */
/* The new node's next should point to the head */
new_node->next = *head;
}
/* We must set HEAD using the following line in order to change the original list */
*head = new_node;
/* The following line would not work because it would only change our local copy of HEAD */
/* head = new_node */
}
/* Prints out a linked list starting at HEAD */
void print_list(struct Node *head) {
struct Node *curr;
for (curr = head; curr != NULL; curr = curr->next) {
printf("%d->", curr->data);
}
printf("NULL\n");
}
/* Iteratively reverses a linked list whose first node is HEAD */
void reverse_list(struct Node **head) {
if (head == NULL || *head == NULL) {
return;
}
struct Node *curr = *head;
struct Node *next = (*head)->next;
curr->next = NULL;
while (next != NULL) {
struct Node *temp = next->next;
next->next = curr;
curr = next;
next = temp;
}
*head = curr;
}
/* Creates a new node with a data field set to DATA and adds the node
to the back of the list pointed to by HEAD */
void add_to_back(Node **head, int data) {
if (head == NULL || *head == NULL) {
return;
}
Node *new_node = create_node(data);
Node *prev;
for (Node *curr = *head; curr != NULL; curr = curr->next) {
prev = curr;
}
prev->next = new_node;
}
test file
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include "linked_list.h"
int main(int argc, char **argv) {
printf("Running tests...\n\n");
Node *head = NULL;
/*********** reverse_list test ***********/
reverse_list(&head);
for (int i = 0; i < 5; ++i) {
add_to_front(&head, i);
reverse_list(&head);
}
int expected_values[] = {3, 1, 0, 2, 4};
Node *curr = head;
for (int i = 0; i < 5; ++i) {
assert(curr->data == expected_values[i]);
curr = curr->next;
}
free_list(head);
printf("Congrats! You have passed the reverse_list test!\n\n");
/************ add_to_back test ***********/
Node *head_2 = NULL;
add_to_back(&head_2, 15);
add_to_back(&head_2, 12);
add_to_back(&head_2, 18);
int expected_values_2[] = {15, 12, 18};
Node *curr_2 = head_2;
for (int i = 0; i < 3; ++i) {
assert(curr_2->data == expected_values_2[i]);
curr_2 = curr_2->next;
}
free_list(head_2);
printf("Congrats! All of the test cases passed!\n");
return 0;
}
The if statement in the function add_to_back
if (head == NULL || *head == NULL) {
return;
}
does not make a sense because it does not allow to append a node to an empty list.
The function can be defined for example like
void add_to_back( Node **head, int data )
{
if ( head == NULL ) return;
Node *new_node = create_node(data);
while ( *head ) head = &( *head )->next;
*head = new_node;
}
Or using your approach then
void add_to_back( Node **head, int data )
{
if ( head == NULL ) return;
Node *new_node = create_node(data);
Node *prev = NULL;
for ( Node *curr = *head; curr != NULL; curr = curr->next )
{
prev = curr;
}
prev == NULL ? ( *head = new_node ) : ( prev->next = new_node );
}
In general this statement
if ( head == NULL ) return;
is also redundant. If the user will pass a null pointer then the function just will have undefined behavior.
On the other hand the function create_node should be written the following way
Node * create_node( int data )
{
struct Node *new_node = malloc(sizeof(struct Node));
if ( new_node != NULL )
{
new_node->data = data;
new_node->next = NULL;
}
return new_node;
}
Correspondingly for example the function add_to_back can be written like
int add_to_back( Node **head, int data )
{
Node *new_node = create_node( data );
int success = new_node != NULL;
if ( success )
{
Node *prev = NULL;
for ( Node *curr = *head; curr != NULL; curr = curr->next )
{
prev = curr;
}
prev == NULL ? ( *head = new_node ) : ( prev->next = new_node );
}
return success;
}
The problem is in the add_to_back() function. Because of first line in that function if (head == NULL || *head == NULL) { return; }, it will keep returning and not executing rest of the code. So, if you print your list after three calls of the add_to_back function, your list has nothing but NULL and that is the reason you are getting a segmentation fault. I did the following change and your code is working fine
`
void add_to_back(Node **head, int data) {
Node *new_node = create_node(data);
if (*head == NULL){
*head = new_node;
return;
}
Node *prev;
for (Node *curr = *head; curr != NULL; curr = curr->next) {
prev = curr;
}
prev->next = new_node;
}
`

What is the problem with this piece of code?

I am writing for deleting the last node of a doubly linked list. But, every time this function is giving me segmentation fault when I have 2 or more than 2 elements in the list.
void deleteEnd()
{
struct node *ptr;
if(head==NULL)
printf("\nList is empty.First add some numbers");
else if(head->next==NULL)
{
head = NULL;
free(head);
}
else
{
ptr = head;
while(ptr->next != NULL)
{
ptr = ptr -> next;
}
ptr -> prev -> next = NULL;
free(ptr);
}
}
Normally, when you are deleting a node from a linked list it is a good practice to pass a reference to the first node of the list as an argument of the function. In your case you are not showing us where the head is coming from, and I think that it could be quite a useful info, and I bet that the error hides there.
That is how the implementation could look like:
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
// insert end node: this is for testing purposes
struct node *insertEnd(struct node *head, int value) {
struct node *ptr, *new_node;
ptr = head;
new_node = (struct node *) malloc(sizeof(struct node));
new_node->data = value;
new_node->next = NULL;
// The list is empty
if (head == NULL) {
head = new_node;
return head;
}
// Non empty list
while (ptr->next != NULL) {
ptr = ptr->next;
}
ptr->next = new_node;
return head;
}
// delete end node
struct node *deleteEnd(struct node *head) {
struct node *ptr, *preptr;
ptr = head;
preptr = NULL;
// The list is empty
if (head == NULL) {
printf("The list is empty. Nothing to delete.\n");
return head;
}
while(ptr->next != NULL) {
preptr = ptr;
ptr= ptr->next;
}
free(ptr);
if (preptr == NULL) {
head = NULL;
}
else {
preptr->next = NULL;
}
return head;
}
int main(void) {
struct node *llist;
llist = NULL;
llist = insertEnd(llist, 10);
llist = insertEnd(llist, 20);
llist = insertEnd(llist, 30);
llist = deleteEnd(llist);
llist = deleteEnd(llist);
llist = deleteEnd(llist);
return 0;
}
It is always a great idea to maintain a global variable head and update it after every push/pop. See this:
struct node
{
int data;
struct node *next;
};
struct node *start = NULL;
struct node *deleteEnd(struct node *start)
{
struct node *ptr = start;
if(ptr==NULL)
{
printf("\nList is empty!!!");
return start;
}
else if(ptr->next == NULL)
{
free(ptr);
start = NULL;
return start;
}
else
{
while((ptr->next)->next!=NULL) //by doing this you dont have to maintain a prev pointer
{
ptr=ptr->next;
}
struct node *temp = ptr->next;
free(temp);
ptr->next = NULL;
return start;
}
}
Hope this helps!!!

Can I insert a node before current node in singly linked list using C?

Is this even possible, because singly linked list does not have pointer to previous, only next? I have a task to do where I have to write a function that inserts a node before current node, and I just can't seem to do it.
EDIT: I made this
void before(List* list, int value) {
Node * temp = new_node(value);
temp->data = value;
temp->next = NULL;
if(list->size == 0){
temp->next = list->current;
list->current = temp;
return;
}else{
for(Node * p = list->head->next; p == list->current; p = p->next){
list->head = list->current;
list->current = list->current->next;
}
temp->next = list->head->next;
list->head->next = temp;
}
}
But for input
insert_after_current(list, 1);
insert_after_current(list, 2);
insert_after_current(list, 3);
insert_after_current(list, 4);
before(list, 5);
I receive output
1 5 2 3 4
Can someone explain why?
As you traverse the list, you need to keep track of the previous node you visited.
Once you find the node you want to insert before, have the previous node point to the new node and have the new node point to the current node.
typedef struct node
{
struct node *next;
}node;
node *insert(node *parent, node *newnode)
{
if(parent && newnode)
{
newnode -> next = parent -> next;
parent -> next = newnode;
}
}
node *insertbefore(node **haystack, node *needle, node *newnode)
{
node *parent = *haystack;
if(needle == *haystack)
{
newnode -> next = *haystack;
*haystack = newnode;
}
else
{
while(parent -> next)
{
if(parent -> next == newnode)
{
insert(parent, newnode);
}
else
{
newnode = NULL;
}
}
}
return newnode;
}

I am trying to write a function that removes all the odd elements from a given linked-list and also returns an adress of

I am trying to write a function that removes all the odd elements from a given linked-list and also returns an adress of a new linked list of the odd elements removed. I find this task quite complicated, and I would be happy if you could help to repair or improve my code.
Here is what I've done by far:
typedef struct list{
int data;
struct list* next;
} List;
List* removeOddValues(List** source)
{
List* curr= source;
List* prev;
List* odd= NULL;
while (curr)
{
if ((curr->data)%2!=0)
{
insertNodeToEnd(&odd, curr->data);
prev->next = curr->next;
}
else
{
prev = curr;
curr= curr->next;
}
}
return odd;
}
List* createNewNode(int newData, List* next)
{
List* newNode = (List)calloc(1, sizeof(List));
newNode->data = newData;
newNode->next = next;
return newNode;
}
void insertNodeToEnd(List** list, type newData) //insert a new node to list //
{
LNode* newNode = createNewNode(newData, NULL);
list->next= newNode;
}
like this:
List* removeOddValues(List **source){
List *curr = *source;
List even = { .next = NULL };
List *e_curr = &even;
List odd = { .next = NULL };
List *o_curr = &odd;
while(curr){
List *next = curr->next;
curr->next = NULL;
if(curr->data % 2)// != 0, odd
o_curr = o_curr->next = curr;//node add to last
else//even
e_curr = e_curr->next = curr;
curr = next;
}
*source= even.next;//update source
return odd.next;
}

Resources