Linked list implementation in c without using double-pointer - c

I have implemented a simple linked list in C language, but can it be implemented without using double-pointer(**).I want to implement same program by using only single pointers.
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
void push(struct node** head_ref, int new_data)
{
struct node* new_node = (struct node*) malloc(sizeof(struct node));
new_node->data = new_data;
new_node->next = (*head_ref);
(*head_ref) = new_node;
}
void append(struct node** head_ref, int 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;
if (*head_ref == NULL)
{
*head_ref = new_node;
return;
}
while (last->next != NULL)
last = last->next;
last->next = new_node;
return;
}
void printList(struct node *node)
{
while (node != NULL)
{
printf(" %d ", node->data);
node = node->next;
}
}
int main()
{
struct node* head = NULL;
append(&head, 6);
push(&head, 7);
push(&head, 1);
append(&head, 4);
printf("\n Created Linked list is: ");
printList(head);
getchar();
return 0;
}
Is it possible to replace "struct node** head_ref" with "struct node* head_ref"?
Changed code after suggestions(still not getting output)
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node* push(struct node* head, int new_data)
{
struct node* new_node = (struct node*) malloc(sizeof(struct node));
new_node->data = new_data;
new_node->next = head;
head = new_node;
return head;
}
struct node* append(struct node* head, int new_data)
{
struct node* new_node = (struct node*) malloc(sizeof(struct node));
struct node *last = head; /* used in step 5*/
new_node->data = new_data;
new_node->next = NULL;
if (head == NULL)
{
head = new_node;
return head;
}
while (last->next != NULL)
last = last->next;
last->next = new_node;
return head;
}
void printList(struct node *node)
{
while (node != NULL)
{
printf(" %d ", node->data);
node = node->next;
}
}
int main()
{
struct node* head = NULL;
head= append(&head, 6);
head=push(&head, 7);
head=push(&head, 1);
head=append(&head, 4);
printf("\n Created Linked list is: ");
printList(head);
getchar();
return 0;
}

Yes, you can rewrite this code using only single pointers, but you would have to change the semantic of your API and the pattern in which it is used.
Essentially, you replace the second level of indirection in
void push(struct node** head_ref, int new_data)
with a client-side assignment, i.e.
struct node* push(struct node* head, int new_data)
This means that instead of
push(&head, num);
the caller will have to write
head = push(head, num);
Same goes for the implementation of append.

Replace (&head,6) with (head,6).As you are not passing the address of the head, on receiving end you have push(struct node* head, int new_data).Rest all have been clarified by above given answer

Another solution is to create an empty node called head, and then create a pointer to that node called list. You can then pass list to all of the functions, like this
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
void push(struct node *list, int new_data)
{
struct node* new_node = malloc(sizeof(struct node));
new_node->data = new_data;
new_node->next = list->next;
list->next = new_node;
}
void append(struct node *list, int new_data)
{
while ( list->next != NULL )
list = list->next;
push( list, new_data );
}
void printList(struct node *node)
{
for ( node=node->next; node != NULL; node=node->next )
printf(" %d ", node->data);
printf( "\n" );
}
int main( void )
{
struct node head = { 0, NULL };
struct node *list = &head;
append(list, 6);
push(list, 7);
push(list, 1);
append(list, 4);
printf("\n Created Linked list is: ");
printList(list);
getchar();
return 0;
}

Related

What is the logical error in my attempt to implement the insertion of nodes in the linked list?

I'm unable to get an output for inserting nodes at the beginning, end, and after a given node. I'm not very sure if there is anything that I missed out in the main(). I'm unable to point out my logical error in the program
`
#include<stdio.h>
#include<stdlib.h>
struct node{
int data;
struct node *next;
};
//Inserts at the begining
void push(struct node **head, int x){
struct node *newnode = (struct node *)malloc(sizeof(struct node));
newnode->data = x;
*head = newnode;
newnode->next = (*head);
*head = newnode;
}
//Insert at the last
void append(struct node **head, int x){
struct node *temp;
struct node* newnode = (struct node*)malloc(sizeof(struct node));
newnode->data = x;
newnode->next = 0;
if(*head == 0){
*head = newnode;
}
temp = *head;
while(temp->next != 0){
temp = temp->next;
}
temp->next = newnode;
}
//inserting at a given node
void insertAfter(struct node* temp, int x){
if(temp == NULL){
printf("previous node cannot be NULL");
}
struct node* newnode = (struct node*)malloc(sizeof(struct node));
newnode->data = x;
newnode->next = temp->next;
temp->next = newnode;
}
void printList(struct node *temp){
while(temp->next != NULL){
printf("%d",temp->data);
}
temp = temp->next;
}
int main(){
struct node *head = NULL;
append(&head,6);
push(&head, 7);
push(&head, 1);
append(&head, 4);
insertAfter(head->next, 8);
printf("Created linked list is:\n");
printList(head);
return 0;
}
`
The output is 1 7 8 6 4
But I'm getting no output and no errors as well
Within the function print_list there can be an infinite loop because this statement
temp = temp->next;
is placed after the while loop
void printList(struct node *temp){
while(temp->next != NULL){
printf("%d",temp->data);
}
temp = temp->next;
}
The function can look for example the following way
void printList( const struct node *head )
{
for ( ; head != NULL; head = head->next )
printf( "%d -> ", head->data );
}
puts( "null" );
}
Pay attention to that within the function push this statement
*head = newnode;
is present twice.
Also the functions are unsafe because there is no check whether memory was allocated successfully within the functions.
For example the function append could be declared and defined the following way
//Insert at the last
int append( struct node **head, int x )
{
struct node *newnode = malloc( sizeof( *newnode ) );
int success = newnode != NULL;
if ( success )
{
newnode->data = x;
newnode->next = NULL;
while ( *head != NULL ) head = &( *head )->next;
*head = newnode;
}
return success;
}

Duplicating a linked list without using recursion

I'm trying to figure out how to duplicate a linked list, and after debugging on Vs code I'm getting a segmentation fault on cuurent->data = temp->data;
and I'm not sure why this is happening.
and this is the code:
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node* next;
};
struct node* head;
struct node* head2;
struct node* Insert(struct node* head, int x)
{
struct node* temp = (struct node*)malloc(sizeof(struct node));
temp->data = x;
temp->next = head;
return temp;
}
void Print(struct node* head)
{
struct node* tmp1 = head;
printf("List is:");
while (tmp1 != NULL) {
printf(" %d", tmp1->data);
tmp1 = tmp1->next;
}
printf("\n");
}
struct node* dupe(struct node* head, struct node* head2)
{
if (head == NULL)
return NULL;
struct node* temp = head;
struct node* prev = NULL;
struct node* cuurent = (struct node*)malloc(sizeof(struct node));
cuurent->data = temp->data;
if (head2 == NULL) {
cuurent->next = head2;
head2 = cuurent;
}
while (temp != NULL) {
temp = temp->next;
cuurent = (struct node*)malloc(sizeof(struct node));
cuurent->data = temp->data;
cuurent->next = prev;
prev = cuurent;
}
return head2;
}
int main(void)
{
head = NULL;
head2 = NULL;
head = Insert(head, 4);
head = Insert(head, 2);
head = Insert(head, 3);
head = Insert(head, 5);
head2 = dupe(head, head2);
Print(head);
Print(head2);
}
As pointed out in the comments,
while (temp != NULL) {
temp = temp->next;
changes the value of temp immediately after guarding against a null pointer value.
This eventually means
cuurent->data = temp->data;
will cause Undefined Behaviour by dereferencing temp when it is the null pointer value.
You can apply the exact same looping principles shown in Print to copy the list. The only difference being you must save a pointer to the first node.
The same principle can be used again when it comes time to free the memory.
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *next;
};
struct node *insert(struct node *next, int x)
{
struct node *n = malloc(sizeof *n);
n->data = x;
n->next = next;
return n;
}
void print_list(struct node *head)
{
printf("List is: ");
while (head) {
printf("%d ", head->data);
head = head->next;
}
printf("\n");
}
void free_list(struct node *head)
{
struct node *t;
while (head) {
t = head->next;
free(head);
head = t;
}
}
struct node *copy_list(struct node *head)
{
struct node *root = NULL;
for (struct node *current; head; head = head->next) {
struct node *new = insert(NULL, head->data);
if (!root)
root = new;
else
current->next = new;
current = new;
}
return root;
}
int main(void)
{
struct node *head = NULL;
head = insert(head, 4);
head = insert(head, 2);
head = insert(head, 3);
head = insert(head, 5);
struct node *head2 = copy_list(head);
print_list(head);
print_list(head2);
free_list(head);
free_list(head2);
}
Output:
List is: 5 3 2 4
List is: 5 3 2 4

Copying elements of a linked list to another linked list in reverse order in C

I'm new to programming in C and taking a course. I'm having trouble with one of the tasks I'm practicing. I'm supposed to Write a program that creates a linked list of 10 characters, then creates a copy of the list in reverse order. I have written (mostly copied) a code, but it only reverses the contents of my linked list, doesn't copy them to a new linked list in reverse order. It's also not working with letters even though I'm using char data type. works fine with numbers.
Here's my code:
#include <stdio.h>
#include <malloc.h>
struct Node
{
char data;
struct Node *next;
};
static void reverse(struct Node **head_ref)
{
struct Node *previous = NULL;
struct Node *current = *head_ref;
struct Node *next;
while (current != NULL)
{
next = current->next;
current->next = previous;
previous = current;
current = next;
}
*head_ref = previous;
}
void push(struct Node **head_ref, char new_data)
{
struct Node *new_node =
(struct Node *)malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = (*head_ref);
(*head_ref) = new_node;
}
void printList(struct Node *head)
{
struct Node *temp = head;
while (temp != NULL)
{
printf("%d ", temp->data);
temp = temp->next;
}
}
int main()
{
struct Node *head = NULL;
char element = NULL;
printf("Enter 10 characters:\n");
for (int i = 0; i <= 9; i++)
{
scanf_s("%d", &element);
push(&head, element);
}
printf("Given linked list\n");
printList(head);
reverse(&head);
printf("\nReversed Linked list \n");
printList(head);
getchar();
}
This for loop
for (int i = 0; i <= 9; i++)
{
scanf_s("%d", &element);
push(&head, element);
}
invokes undefined behavior because there is used an incorrect conversion specifier %d with an object of the type char,
You need to write
for (int i = 0; i <= 9; i++)
{
scanf_s( " %c", &element, 1 );
push(&head, element);
}
Pay attention to the blank before the conversion specifier %c in the format string. This allows to skip white space characters in the input stream.
As for the function then it can be declared and defined the following simple way using the function push that you already defined
struct Node * reverse_copy( const struct Node *head )
{
struct Node *new_head = NULL;
for ( ; head != NULL; head = head->next )
{
push( &new_head, head->data );
}
return new_head;
}
And in main you can write something like
struct Node *second_head = reverse_copy( head );
Take into account that the function push would be more safer if it would process the situation when memory allocation for a node failed.
To create a copy in reverse order, create a new list with the same values as the original list but prepend the new nodes using the push function.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
struct Node {
char data;
struct Node *next;
};
void prepend(struct Node **head_ref, char new_data) {
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = (*head_ref);
(*head_ref) = new_node;
}
void append(struct Node **head_ref, char new_data) {
struct Node *new_node = (struct Node *)malloc(sizeof(struct Node));
struct Node *node = *head_ref;
new_node->data = new_data;
new_node->next = NULL;
if (!node) {
*head_ref = new_node;
} else {
while (node->next)
node = node->next;
node->next = new_node;
}
}
void printList(const struct Node *head) {
const struct Node *temp = head;
while (temp != NULL) {
printf("%c ", temp->data);
temp = temp->next;
}
printf("\n");
}
struct Node *copy_reverse(struct Node *list) {
struct Node *new_list = NULL;
while (list) {
prepend(&new_list, list->data);
list = list->next;
}
return new_list;
}
void freeList(struct Node *list) {
while (list) {
struct Node *node = list;
list = list->next;
free(node);
}
}
int main() {
struct Node *head = NULL;
char element;
printf("Enter 10 characters:\n");
for (int i = 0; i < 10; i++) {
scanf_s("%c", &element);
push(&head, element);
}
printf("Given linked list\n");
printList(head);
struct Node *copy = copy_reverse(head);
printf("\nReversed Linked list \n");
printList(copy);
freeList(head);
freeList(copy);
getchar();
}
You're almost there. All it needs is one tweak. In reverse, you need to create a new copy of the current node and use that instead. Also, since you'll be ending up with a second list and not altering the original, you should return the new list from reverse.
static struct Node* reverse(const struct Node* head_ref)
{
struct Node* previous = NULL;
const struct Node* current = head_ref;
struct Node* copy;
while (current != NULL) {
copy = malloc(sizeof(*copy));
if (copy == NULL) {
// handle error
}
copy->data = current->data;
copy->next = previous;
previous = copy;
current = current->next;
}
return previous;
}
You can also make the loop prettier by converting it to a for loop.
for (current = head_ref; current != NULL; current = current->next) {
Finally, when you print out the list, you're using %d in the printf format string. %d will print the char as an integer. To print out the actual character, use %c instead.

how to implement linked list

#include <stdio.h>
#include <stdlib.h>
struct Node {
int data;
struct Node* next;
struct Node* prev;
};
void push(struct Node** head_ref, int new_data) {
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = (*head_ref);
new_node->prev = NULL;
if ((*head_ref) != NULL)(*head_ref)->prev = new_node;
(*head_ref) = new_node;}
void append(struct Node** head_ref, int new_data){
/* 1. allocate node */
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
struct Node* last = *head_ref; /* used in step 5*/
/* 2. put in the data */
new_node->data = new_data;
/* 3. This new node is going to be the last node, so
make next of it as NULL*/
new_node->next = NULL;
/* 4. If the Linked List is empty, then make the new
node as head */
if (*head_ref == NULL) {
new_node->prev = NULL;
*head_ref = new_node;
return;}
/* 5. Else traverse till the last node */
while (last->next != NULL)
last = last->next;
/* 6. Change the next of last node */
last->next = new_node;
/* 7. Make last node as previous of new node */
new_node->prev = last;
return;}
void insertAfter(struct Node* prev_node, int new_data){
/*1. check if the given prev_node is NULL */
if (prev_node == NULL) {
printf("the given previous node cannot be NULL");
return;}
/* 2. allocate new node */
struct Node* new_node = (struct Node*)malloc(sizeof(struct Node));
/* 3. put in the data */
new_node->data = new_data;
/* 4. Make next of new node as next of prev_node */
new_node->next = prev_node->next;
/* 5. Make the next of prev_node as new_node */
prev_node->next = new_node;
/* 6. Make prev_node as previous of new_node */
new_node->prev = prev_node;
/* 7. Change previous of new_node's next node */
if (new_node->next != NULL)
new_node->next->prev = new_node;}
void printList(struct Node* node){
struct Node* last;
printf("\nTraversal in forward direction \n");
while (node != NULL) {
printf(" %d ", node->data);
last = node;
node = node->next;}
printf("\nTraversal in reverse direction \n");
while (last != NULL) {
printf(" %d ", last->data);
last = last->prev;
}}
void sortedInsert(struct Node** head, int new_data) {
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = NULL;
struct Node* temp;
if ((*head) == NULL || (new_node->data) > (*head)->prev->data) {
append(head, new_data);
return;
}
if ((new_node->data) < ((*head)->data)) {
push(head, new_data);
return;
}
temp = (*head)->next;
while ((temp->data) < (new_node->data)) {
temp = temp->next;
}
insertAfter(head, new_data);
}
int main() {
struct Node* head = NULL;
sortedInsert(&head, 0);
sortedInsert(&head, 9);
sortedInsert(&head, 4);
sortedInsert(&head, 3);
sortedInsert(&head, 34);
sortedInsert(&head, 15);
printf("\n Created Linked list is: ");
printList(head);
return 0;}
I am trying to write a C program where data must be inserted in a ordered way (smaller to higher)
When I run the code program gives error due to the note:
expected 'struct Node *' but argument is of type 'struct Node **'
how can I fix this problem , I have looked up to the other solutions such as : What does the warning - expected ‘struct node **’ but argument is of type ‘struct node **’ mean?
but those couldnt resolve my issue.
Any help is appreciated
insertAfter(head, new_data);
how can I fix this problem
You forgot to dereference struct Node** head as you correctly did at other places in the function sortedInsert; to get the argument type right, it would be insertAfter(*head, new_data).
But still the insertion logic isn't quite right; here's a corrected version:
void sortedInsert(struct Node** head, int new_data) {
// new node is allocated in append(), push() or insertAfter()
struct Node* temp;
if ((*head) == NULL || new_data < (*head)->data) {
push(head, new_data);
return;
}
temp = *head;
while (temp->next && temp->next->data < new_data) {
temp = temp->next;
}
insertAfter(temp, new_data);
}
When you are using the functions you declared you should pass a reference (address) to the head not the head itself as this what your code requires.
As an example, use append(&head, 3) instead of append(head, 3)

Segmentation fault in a simple linked list?

I am trying to implement a simple linked list. When I tried compiling its not showing any errors. But when while running it, its giving segmentation fault. I analysed the code but I'm not able to find any fault, might be wrong in my side, I don't know.
Please help me find the fault in the code.
Thanks in advance for all the suggestions
#include<stdio.h>
#include<stdlib.h>
struct node{
int data;
struct node* next;
};
void push(struct node** first, int data){
struct node* new_node;
new_node =(struct node*)malloc(sizeof(struct node));
/*printf("Enter the data\n");
scanf("%d",&new_node->data);*/
new_node->data = data;
new_node->next= NULL;
if(*first==NULL){
*first = new_node;
return;
}
new_node->next= *first;
*first = new_node;
}
void insert_node(struct node* prv, int data){
if(prv==NULL){
printf("previous node cannot be null\n");
return;
}
struct node* new_node;
new_node = (struct node*)malloc(sizeof(struct node));
/* printf("Enter the data\n");
scanf("%d",&new_node->data); */
new_node->data = data;
new_node->next = prv->next;
prv->next = new_node;
}
void append(struct node** first, int data){
struct node* last;
last = (struct node*)malloc(sizeof(struct node));
/* printf("Enter the data\n");
scanf("%d",&last->data); */
last->data = data;
last->next = NULL;
struct node* pre = *first;
if(*first == NULL){
*first = last;
}
while(pre->next!=0)
{pre = pre->next;}
last->next = pre->next;
pre->next = last;
}
void print(struct node* first){
if(first==NULL){
printf("There is no linked list to print\n");
}
while(first!=NULL){
printf("%d ",first->data);
first = first->next;
}
printf("\n");
}
int main()
{
struct node* first=NULL;
append(&first, 6);
push(&first, 7);
push(&first, 1);
append(&first, 4);
insert_node(first->next, 8);
printf("The Linked List is: \n");
print(first);
return 0;
}
You got your segv inside the append function:
void append(struct node** first, int data){
struct node* last;
last = (struct node*)malloc(sizeof(struct node));
last->data = data;
last->next = NULL;
struct node* pre = *first; // <-- pre = NULL
if(*first == NULL){
*first = last;
}
while(pre->next!=0)
{pre = pre->next;} //<-- referencing NULL
last->next = pre->next;
pre->next = last;
}
Solution: add a return inside the if.
if(*first == NULL){
*first = last;
return;
}

Resources