Creating an entire doubly linked list in one function - c

I'm new to DSA and currently learning linked-list. I was trying to create an entire linked list in one function. The first scanf in createList function doesn't seem to assign the input to the address provided(i.e. &n). I tried printing n right after scanf. It doesn't print n to console at all.
As a result, the output is not the way I expected. I can't figure out why.
//ENTIRE CODE HERE
#include<stdio.h>
#include<stdlib.h>
struct node {
struct node* prev;
int data;
struct node* next;
};
void print_nodes(struct node* );
struct node* addToEmpty(struct node*, int);
struct node* addAtEnd(struct node*, int);
struct node* createList(struct node*);
int main() {
struct node* head = NULL;
head = createList(head);
print_nodes(head);
}
void print_nodes(struct node* head) {
struct node* ptr = head;
while (ptr != NULL) {
printf("%d ", ptr->data);
ptr = ptr->next;
}
printf("\n");
}
struct node* addToEmpty(struct node* head, int data) {
struct node* temp = malloc(sizeof(struct node));
temp->prev = NULL;
temp->data = data;
temp->next = NULL;
head = temp;
return head;
}
struct node* addAtEnd(struct node* head, int data) {
struct node* tp = head;
struct node* temp = malloc(sizeof(struct node));
temp->prev = NULL;
temp->data = data;
temp->next = NULL;
while (tp->next != NULL) {
tp = tp->next;
}
tp->next = temp;
temp->prev = tp;
return head;
}
struct node* createList(struct node* head) {
int n, data, i;
printf("Enter the number of nodes: ");
scanf("%d ", &n);
if (n == 0)
return head;
printf("Enter the element of node 1: ");
scanf("%d ", &data);
head = addToEmpty(head, data);
for (i = 1; i < n; i++) {
printf("Enter the element of node %d: ", i + 1);
scanf("%d", &data);
head = addAtEnd(head, data);
}
return head;
}

your problem is so simple , instead of scanf("%d ", &n); , just write scanf("%d", &n); by which I mean to remove the wite space after %d as it's producing some strange behavior in your case , as if you refer to scanf() manual page , they say that :
A sequence of white-space characters (space, tab, newline,
etc.; see isspace(3)). This directive matches any amount
of white space, including none, in the input.
which is supposed to ignore any whitespace after the number entered till getting a valid char.
and here is the full code but with this only small modification:
#include<stdio.h>
#include<stdlib.h>
struct node {
struct node* prev;
int data;
struct node* next;
};
void print_nodes(struct node* );
struct node* addToEmpty(struct node*, int);
struct node* addAtEnd(struct node*, int);
struct node* createList(struct node*);
int main() {
struct node* head = NULL;
head = createList(head);
print_nodes(head);
}
void print_nodes(struct node* head) {
struct node* ptr = head;
while (ptr != NULL) {
printf("%d ", ptr->data);
ptr = ptr->next;
}
printf("\n");
}
struct node* addToEmpty(struct node* head, int data) {
struct node* temp = malloc(sizeof(struct node));
temp->prev = NULL;
temp->data = data;
temp->next = NULL;
head = temp;
return head;
}
struct node* addAtEnd(struct node* head, int data) {
struct node* tp = head;
struct node* temp = malloc(sizeof(struct node));
temp->prev = NULL;
temp->data = data;
temp->next = NULL;
while (tp->next != NULL) {
tp = tp->next;
}
tp->next = temp;
temp->prev = tp;
return head;
}
struct node* createList(struct node* head) {
int n, data, i;
printf("Enter the number of nodes: ");
scanf("%d", &n);
if (n == 0)
return head;
printf("Enter the element of node 1: ");
scanf("%d", &data);
head = addToEmpty(head, data);
for (i = 1; i < n; i++) {
printf("Enter the element of node %d: ", i + 1);
scanf("%d", &data);
head = addAtEnd(head, data);
}
return head;
}
and this is the output:
Enter the number of nodes:3
Enter the element of node 1:1
Enter the element of node 2:2
Enter the element of node 3:3
1 2 3

I tried out your code and found issues with the space in the literal string in the "scanf" statements. I see that someone else found that and offered up the solution to that with the cleanup of the "scanf" statements. I would say that if you are to accept an answer, select the first one. However, I just wanted to also offer up my code snippet with a couple of additional tweaks.
#include<stdio.h>
#include<stdlib.h>
struct node
{
struct node* prev;
int data;
struct node* next;
};
void print_nodes(struct node* );
struct node* addToEmpty(struct node*, int);
void addAtEnd(struct node*, int); /* No requirement for a node to be returned as the pointers are all set up in the function */
struct node* createList(struct node*);
int main()
{
struct node* head = NULL;
head = createList(head);
print_nodes(head);
}
void print_nodes(struct node* head)
{
struct node* ptr = head;
while (ptr != NULL)
{
printf("%d ", ptr->data);
ptr = ptr->next;
}
printf("\n");
}
struct node* addToEmpty(struct node* head, int data)
{
struct node* temp = malloc(sizeof(struct node));
temp->prev = NULL;
temp->data = data;
temp->next = NULL;
//head = temp;
return temp; /* Return the pointer to the new struct - no need for update of head here */
}
void addAtEnd(struct node* head, int data)
{
struct node* tp = head;
struct node* temp = malloc(sizeof(struct node));
temp->prev = NULL;
temp->data = data;
temp->next = NULL;
while (tp->next != NULL)
{
tp = tp->next;
}
tp->next = temp;
temp->prev = tp;
return;
}
struct node* createList(struct node* head)
{
int n, data, i;
printf("Enter the number of nodes: ");
scanf("%d", &n);
if (n == 0)
return head;
printf("Enter the element of node 1: ");
scanf("%d", &data);
head = addToEmpty(head, data);
for (i = 1; i < n; i++)
{
printf("Enter the element of node %d: ", i + 1);
scanf("%d", &data);
addAtEnd(head, data);
}
return head;
}
First off, since there is not a need to return a "struct" pointer in the function "addAtEnd", I revised that to be a "void" function return signature. Second, in the "addToEmpty" function, one can just return the pointer value in "temp" instead of placing the value into the input parameter "head"; however, it works either way. It is just a matter of choice.
As a sample, here is some output data at the terminal.
#Una:~/C_Programs/Console/CompleteList/bin/Release$ ./CompleteList
Enter the number of nodes: 4
Enter the element of node 1: 65535
Enter the element of node 2: 2458
Enter the element of node 3: -44
Enter the element of node 4: 3258779
65535 2458 -44 3258779
I would suggest trying out both iterations.

Other answers have pointed at the specific problem you experienced (bad scanf() parameter string).
Going beyond that, however, there are two other "issues(?)".
First is to "create an entire linked list in one function".
In your code, main() calls only one function, but that function uses two "helper" functions to get the job done.
Every line of code is an opportunity for a bug to lurk unseen.
Re-using code is a way to reduce the chances for bugs to appear.
Secondly, the code appears to be correct, but does not prove that the doubly linked list is anything more than a singly linked list.
Both of these matters are addressed below creating (in one function, and later demonstrating) a circular doubly linked list.
Comments explain changes from the original code to this version.
Finally, an additional function is used here to prevent memory leaks.
#include <stdio.h>
typedef struct node { // Using 'typedef' saves lots of typing (and reading
int data;
struct node *next;
struct node *prev; // conventional layout of members
} node_t; // Notice '_t' as conventional suffix for user declared datatypes
node_t *print_nodes( node_t *head ) { // return pointer for use by caller
if( head ) { // insurance against NULL pointer
node_t *pn = head;
printf( "Forward: " ); // exercise circular LL in both directions
do {
printf( "%d ", pn->data );
pn = pn->next; // NB: 'next'
} while( pn != head ); // circular, not linear! One full circuit
puts( "" );
printf( "Reverse: " );
pn = pn->prev; // shift 'back' one node to begin
do {
printf( "%d ", pn->data );
pn = pn->prev; // NB: 'prev'
} while( pn != head->prev ); // circular, not linear! One full circuit
puts( "" );
}
return head;
}
node_t *createList() { // Create "one ring to rule them all"
int n = 0; // ALWAYS initialise variables
do {
printf( "Number of nodes (min 3): ");
scanf( "%d", &n ); // 'while' protects against bad input
} while( n < 3 );
node_t *head = NULL;
for( int i = 0; i < n; i++ ) {
printf( "Enter the element of node %d: ", i + 1 );
node_t *pn = (node_t *)calloc( 1, sizeof *pn ); // 'calloc()' zeros the block
/* check 'pn == NULL' omitted for brevity */
scanf("%d", &pn->data ); // read directly into destination (fewer variables)
if( head == NULL )
head = pn->prev = pn->next = pn; // 1st node, circular
else {
pn->prev = head->prev; // other nodes spliced-in ahead of 'head'
pn->next = head;
head->prev->next = pn;
head->prev = pn;
}
}
return head;
}
void freemem( node_t *head ) { // VERY important to respect "heap" storage!
if( head == NULL ) return;
node_t *pn = head; // traverse releasing nodes along the way
do {
node_t *pdel = pn;
pn = pn->next;
free( pdel );
} while( pn != head );
}
int main() {
// create, print, release, done...
freemem( print_nodes( createList() ) );
return 0;
}
Output
Number of nodes (min 3): 5
Enter the element of node 1: 42
Enter the element of node 2: 56
Enter the element of node 3: 10
Enter the element of node 4: -5
Enter the element of node 5: 256
Forward: 42 56 10 -5 256
Reverse: 256 -5 10 56 42
This code implements and proves a circular doubly linked list. The example can be trivially adapted to a linear dbl-LL by severing the connection between head and head->prev after the ring has been formed, and then making necessary adjustments at other locations to account for the change.

Related

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.

C programming - Reverse a linked link by iterative method

I am trying to reverse a linked by iterative method. Magically, after watching tutorial and trying to recode myself, the program works successfully. However, when I review the code, I hit a question: in line 23, why we must use temp1->next instead of temp1? When traversing to the end of the linked list, which case we use the condition (the node != NULL)? In which case we use (the link of the node ! = NULL)? I fully appreciate it if anyone can enlighten me.
#include <stdio.h>
#include <stdlib.h>
struct Node
{
int data;
struct Node* next;
};
struct Node* Insert(struct Node* head, int data)
{
struct Node* temp = (struct Node*) malloc(sizeof(struct Node));
temp->data = data;
temp->next = NULL;
//If the list is empty
if (head == NULL)
{
head = temp;
}
else //The list is not empty
{
struct Node* temp1 = head;
while (temp1->next != NULL)
{
temp1 = temp1->next;
}
temp1->next = temp;
}
return head;
}
void Print(struct Node* head)
{
struct Node* temp = head;
while (temp != NULL)
{
printf("%d ", temp->data);
temp = temp->next;
}
printf("\n");
}
struct Node* Reverse(struct Node* head)
{
struct Node* *prev, *current, *next;
current = head;
prev = NULL;
while (current != NULL)
{
next = current->next;
current->next = prev;
prev = current;
current = next;
}
head = prev;
return head;
}
int main()
{
struct Node* head = NULL;
printf("Enter the length of the linked list you want to create: ");
int length;
scanf("%d", &length);
printf("Enter the value you want to input: ");
int i;
for (i = 0; i < length; i++)
{
int x;
scanf("%d", &x);
head = Insert(head, x);
}
printf("Given linked list\n");
Print(head);
head = Reverse(head);
printf("\nReversed linked list \n");
Print(head);
return 0;
}
In that case, inside the while condition, on line 23, you can notice that the program is using temp1 = temp1->next, if you change the condition to temp1 != NULL when it reaches the last element of linked list it'll collect trash from memory or even result in an error, because NULL don't have a next position.
So, you use temp1 != NULL if you are accessing the data inside the list and temp1->next != NULL if you are manipulating the next positions of the linked list.
Because temp1->next at the end of the linked list is NULL, however, the last node has data, if you use temp1 == NULL you would say that the last node is NULL, which is not the case. So you want to end the loop when the "pointer to the next node" is NULL, not when the next node is NULL.

In a program using linked-list no output is being shown in c

i'm working on a program in c language in which I have to use linked-list and in this program I have to insert the new node at the start of the linked-list if the user pass the value of the place 0 and also insert the new node at the end of the linked-list if the user pass the value of the place 1 in the choice variable. But i'm not getting any output on console and my program ends by just writing Output:
I can't figure out the problem in my code and here's my code.
/*
program for making nodes and adding them in memory as per 0
and 1
0 means that insert the number at front , in other words insert number after head
1 means insert number at the last place
First you need to input a number and then enter the place you want to insert it by giving input as 0 and 1
*Recall what does 0 and 1 mean by looking at line 5-7 respectively.
Just like
5 0 6 1 7 0 8 1
*/
#include <stdio.h>
#include <stdlib.h>
// declaring struct with typedef for ease of use
typedef struct node
{
int data;
struct node *next;
}node;
// declarations of functions use for this program respectively
void free_node(struct node *head);
void insert_at_beg(int num, struct node *head);
void insert_at_end(int num, struct node *head);
void print_node(struct node *head);
int main(void)
{
struct node *head = NULL;
int n;
// taking input
printf("Input number of nodes: ");
scanf("%d",&n);
int num, choice;
printf("\nInput data for nodes->\n");
// loop which takes value and choice
for (int i = 0; i < n; i++)
{
num = 0, choice = 0;
printf("\nInput data for the %d node: ", i+1);
scanf("%d",&num);
do
{
printf("Input place for the %d node: ", i+1);
scanf("%d",&choice);
}
while (choice != 1 && choice != 0);
if (choice == 0)
{
// function to insert node at front of head
insert_at_beg(choice, head);
}
else
{
// function to insert node at last place
insert_at_end(choice, head);
}
}
// function to print nodes
print_node(head);
// function to free memory made by malloc()
free_node(head);
}
// function to free the nodes
void free_node(struct node *head)
{
struct node *temp = head;
while(temp != NULL)
{
free(temp);
temp = temp->next;
}
}
// function for inserting number at front
void insert_at_beg(int num, struct node *head)
{
struct node *new_node = malloc(sizeof(node));
if (new_node == NULL)
{
printf("Can't allocate memory.");
exit (1);
}
new_node->data = num;
new_node->next = head;
head = new_node;
}
// function for inserting node at end
void insert_at_end(int num, struct node *head)
{
struct node *new_node, *last_node = NULL;
new_node = malloc(sizeof(node));
if (new_node == NULL)
{
printf("Can't allocate memory.");
exit (1);
}
if (head == NULL)
{
new_node->data = num;
new_node->next = NULL;
head = new_node;
}
last_node = head;
new_node->data = num;
new_node->next = NULL;
while (last_node->next != NULL)
{
last_node = last_node->next;
}
last_node->next = new_node;
}
//function for printing nodes
void print_node(struct node *head)
{
printf("\nOutput: \n");
struct node *temp = head;
while(temp != NULL)
{
printf("%d ",temp->data);
temp = temp->next;
}
}
You need to pass the pointer to the head node by reference to your functions insert_at_beg and insert_at_end and desirable to the function free_node.
Passing by reference in C means passing an object indirectly through pointer to it.
So for example the function insert_at_beg can look the following way. Pay attention to that such a function should not issue any message. It is the caller of the function that decides whether to output a message or not.
// function for inserting number at front
int insert_at_beg( struct node **head, int num )
{
struct node *new_node = malloc( sizeof( struct node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = num;
new_node->next = *head;
*head = new_node;
}
return success;
}
Correspondingly the function insert_at_end can look the following way
// function for inserting node at end
int insert_at_end( struct node **head, int num )
{
struct node *new_node = malloc( sizeof( struct node ) );
int success = new_node != NULL;
if ( success )
{
new_node->data = num;
new_node->next = NULL;
while ( *head != NULL )
{
head = &( *head )->next;
}
*head = new_node;
}
return success;
}
The function free_node has undefined behavior because you are using the pointer temp to access the memory that was already freed.
free(temp);
temp = temp->next;
The function can be defined the following way
// function to free the nodes
void free_node( struct node **head )
{
while( *head != NULL )
{
struct node *temp = *head;
head = &( *head )->next;
free( temp );
}
}
The functions can be called like
insert_at_end( &head, num );
or
if ( !insert_at_end( &head, num ) )
{
printf( "There is no enough memory to insert the value %d\n", num );
}
The parameter of the function print_node should have the qualifier const because the list is not changed within the function
//function for printing nodes
void print_node( const struct node *head )
{
printf("\nOutput: \n");
const struct node *temp = head;
//...
C is a pass-by-value language -- values passed to functions are copied and changes to the parameter in the function do not affect the caller. So head never becomes non-null in main; the assignment to head in insert_at_end is local and does not update the head pointer in main.

can't get response from a function in c [closed]

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.

What's with the program why is it not printing any result?

struct node{
int data; struct node *next;
};
void push(struct node* head, struct node* n){
if(n!= NULL){
if(head==NULL)
head = n;
else {
n->next = head;
head = n;
}
} else printf("Cannot insert a NULL node");
}
struct node* pop(struct node* head){
if(head!=NULL){
struct node *n = head;
head = head->next;
return n;
} else {
printf("The stack is empty");
return NULL;
}
}
int main(){
int i;
struct node *head = NULL, *n;
for(i=15;i>0;i--){
struct node *temp = malloc(sizeof(struct node));
temp -> data = i;
temp->next = NULL;
push(head,temp);
}
n = head;
while(n!=NULL){
printf("%d ",n->data);
n=n->next;
}
return 0;
}
You need to pass the address of the pointer head to the function push. I your case the head is not getting modified because you are only passing the value in the head.
void push(struct node** head, struct node* n){
if(n!= NULL){
if(*head==NULL)
*head = n;
else {
n->next = *head;
*head = n;
}
} else printf("Cannot insert a NULL node");}
int main(){
int i;
struct node *head = NULL, *n;
for(i=15;i>0;i--){
struct node *temp = (struct node *)malloc(sizeof(struct node));
temp -> data = i;
temp->next = NULL;
push(&head,temp);
}
n = head;
while(n!=NULL){
printf("%d ",n->data);
n=n->next;
}
return 0;}
You are passing the head pointer by value to the function push(head,temp);. The changes to head done inside push will not be reflected in the main() function.
You should pass address of head to push().
push(&head, temp);
and inside push():
*head = n;
Similar change will be required for pop(). You can verify what I am saying by adding a printf inside the loop in main() as: printf("%p\n", head);. The value of head will remain unchanged.
BTW, it is good practice to add a \n at the end of statement inside printf, it flushes the stdout stream immmediately hence your output is printed immediately on stdout (your computer screen).

Resources