My code works for elements which are at the start of the linked list but not for the ones in the middle or the end. Appreciate your help!
void remove(){
if (!head)
printf("\nNo nodes to delete. List is empty.");
else{
int n;
struct node* help = head;
printf("Enter an element to delete: ");
scanf("%d", &n);
if(head->data == n){
help-> next->prev = 0;
head = help -> next;
} else{
while(help -> next){
if(help -> data == n){
help -> next -> prev = help -> prev;
help -> prev -> next = help -> next;
}
else help = help -> next;
}
}
}
}
First, use NULL not 0 for meaning NULL. In C, you need to. In C++ it's optional, but you tagged the question C.
help-> next->prev = 0;
You never check to see if there is a second element. If the list only has one element, this fails -- so it doesn't even always work for the first element.
while(help -> next){
if(help -> data == n){
This will stop you from ever deleting the last element, since you stop looking at the list once you get to (but before you deal with) the last element. But even if you didn't, the next lines:
help -> next -> prev = help -> prev;
help -> prev -> next = help -> next;
will cause you to crash if it's the last one, since it's not checking that there is another element after.
Also, the spaces before and after the arrow -> is pretty uncommon. I'd suggest not doing that anymore.
struct node *head, *tail; //global head & tail
int delete_item() {
int del_data = 0;
struct node *item = head, *tmp;
scanf("%d", &del_data);
while(item){
if(item->data == del_data){
tmp = item;
if(item->next){
//it's not tail
item->next->prev = item->prev;
}
else {
//it's tail
tail = item->prev;
if(tail)
tail->next = NULL;
}
if(item->prev){
//it's not head
item->prev->next = item->next;
}
else {
//it's head
head = item->next;
if(head)
head->prev = NULL;
}
//free memory
free(tmp);
}
//move forward
item = item->next;
}
return 0;
}
I was accidentally working on that until I found this way to delete the node
in given position :
void delete (int n) {
struct node *temp = head;
if (n == 1) {
head = temp->next;
(temp->next)->prev = head;
free(temp);
return;
}
for (int i = 0; i < n - 1; i++) {
temp = temp->next;
}
if (temp->next != NULL) {
(temp->next)->prev = temp->prev;
(temp->prev)->next = temp->next;
} else {
(temp->prev)->next = NULL;
}
free(temp);
}
Related
I created a program in c which :
Creates a simple linked list in c in which I store letters
Print the content of every node
delete the last node
Print the content of the list again
The problem is with the "delete_last" function because prints in terminal an infinite loop (I believe that the problem is invoked when I use free funtion.)
#include<stdio.h>
#include<stdlib.h>
typedef struct node {
char xar;
struct node *next;
}Node;
void insert_list(Node **head , int len)
{
char x;
Node **list;
Node *node1 , *node2;
node1=(Node*)malloc(sizeof(Node));
printf("Give 5 characters : ");
x=getchar();
node1->xar = x;
node1->next=NULL;
list=&node1;
int i=0;
for(i=1 ; i < len ; i++)
{ x=getchar();
node2 = (node*)malloc(sizeof(node));
node2->xar = x;
node2->next = NULL;
(*list) -> next = node2;
list = &(*list) -> next ;
}
*head=node1;
}
void print_list(Node *head)
{
Node**lpp;
for(lpp=&head ; *lpp!=NULL ; lpp=&(*lpp)->next)
{
printf("\n the chars are %c" , (*lpp)->xar);
}
}
void delete_last(Node *head)
{
Node **lpp;
lpp=&head;
while((*lpp)->next!=NULL)
{
lpp=&(*lpp)->next;
}
free(*lpp);
}
int main()
{
Node *kefali ;
kefali = NULL;
insert_list(&kefali , 5);
print_list(kefali);
printf("\n");
delete_last(kefali);
print_list(kefali);
return 0;
}
You mustn't access to freed objects.
In the delete_last functon, you called free() for one of the nodes, but you didn't update any pointers there. This will have the following call of print_list access a freed object, invoking undefined behavior.
You should add
*lpp = NULL;
after
free(*lpp);
To get the freed node out of the list.
Note that this won't work for removing the first (only) element in the list because the head is passed as a copy. You should change the function to accept a pointer to the head pointer to enable it remove the first element.
Your delete_last lacks a way of telling that the last element was deleted. Either pass a pointer to head or return a new head.
Further, it's way to complicated. Using lpp as pointer to pointer is not necessary - it only complicates the code. Keep it simple.
Here is an example which returns the new head.
Node* delete_last(Node *head)
{
if (head == NULL) return NULL; // empty list
if (head->next == NULL)
{
// Only one element...
free(head);
return NULL;
}
Node *prev = head;
Node *lpp = prev->next;
while (lpp->next)
{
prev = lpp;
lpp = prev->next;
}
prev->next = NULL;
free(lpp);
return head;
}
and call it like:
head = delete_last(head);
Here is an example which takes a pointer to head.
Node* delete_last(Node **head)
{
if (head == NULL) exit(1); // illegal call
if (*head == NULL) return NULL; // empty list
if ((*head)->next == NULL)
{
// Only one element...
free(*head);
*head = NULL;
return;
}
Node *prev = *head;
Node *lpp = prev->next;
while (lpp->next)
{
prev = lpp;
lpp = prev->next;
}
prev->next = NULL;
free(lpp);
}
and call it like:
delete_last(&head);
You do not update the previous node (you need to keep track on it when iterating)
This makes no sense as you take reference to the local variable head and it does not change the the head of list when last element is deleted.
Node **lpp;
lpp=&head;
To prevent double-pointer function returns the head. Assign it when called. If return value is NULL the last element was deleted
Node *delete_last(Node *head)
{
Node *lpp = NULL, *prev;
if(head)
{
lpp=head -> next;
prev = head;
while(lpp->next)
{
prev = lpp;
lpp = lpp -> next;
}
if(prev == head && lpp == NULL)
{
free(head);
head = NULL; //empty list
}
else
{
free(lpp);
prev -> next = NULL;
}
}
free(lpp);
return head;
}
You can also use double pointer to modify the head when needed:
void delete_last(Node **head)
{
Node *lpp = NULL;
if(head && *head)
{
if(!(*head) -> next)
{
free(*head);
*head = NULL;
}
else
{
lpp = *head;
while(lpp -> next -> next)
{
lpp = lpp -> next;
}
free(lpp -> next);
lpp -> next = NULL;
}
}
}
I need to create a new function when adding a new element, it places it in the list so that the list stays in sorted order. I am not sure if my implementation is correct, my first try, with my group members, gave a segmentation fault. When I tried to do it on my own, it did not do anything. Any help will be appreciated. Here is my code:
header file:
typedef struct s{
int value;
struct s *next, *previous;
} node, *node_ptr;
c file:
#include <stdio.h>
#include <stdlib.h>
#include "double.h"
void
print_list(node_ptr list) {
// walk the list to print out the contents
while (list) {
printf("%d ",list->value);
list = list->next;
}
printf("\n");
}
void delete_list(node_ptr list) {
// walk the list to delete the elements
node_ptr t;
while (list) {
t = list;
list = list->next;
free(t);
}
}
node_ptr new_node(int value) {
node_ptr t = (node_ptr)malloc(sizeof(node));
t->value = value;
t->next = t->previous = NULL;
return t;
}
node_ptr add_to_back(node_ptr list, int value) {
node_ptr t = list;
node_ptr s = new_node(value);
// special case: starting with an empty list
if (t == NULL) return s;
// at this point we know there is a least one element in
// the list
while (t->next != NULL) // walk the list looking for the last element
t = t->next;
// we are at the end so now we arrange the pointers
t->next = s;
s->previous = t;
return list;
}
// my implementation after some research
node_ptr add_sorted(node_ptr list, int value) {
node_ptr temp = list;
node_ptr newNode;
if(temp == NULL || temp->value < newNode->value)
{
newNode->next = temp;
temp = newNode;
}
else
{
while(temp != NULL && temp->value < value)
{
temp = temp->next;
}
newNode->next = temp->next;
temp->next = newNode;
}
return newNode;
}
// second implementation with team
/*
node_ptr add_sorted2(node_ptr list, int value) {
// This is the function you need to implement
// when adding a new element place it in the list so that the list stays in sorted order.
node_ptr temp = list;
node_ptr n = new_node(value);
if(temp == NULL)
{
temp->value = value;
temp->next = NULL;
return n;
}
else if(temp->next != NULL) {
while(temp->next != NULL) {
if(temp->value <= value) {
n->next = temp->next;
temp->next = n;
return n;
}
else if(temp->value > value) {
temp = temp->next;
}
else {
temp->next = n;
return n;
}
}
}
return n;
}
*/
int
main() {
int in_val;
node_ptr my_list = NULL;
node_ptr sorted_list = NULL;
scanf("%d",&in_val);
while (in_val > 0) { // going to read input until see 0 or negative
my_list = add_to_back(my_list,in_val);
sorted_list = add_sorted(sorted_list,in_val);
scanf("%d",&in_val);
}
printf("List:\n");
print_list(my_list);
printf("Sorted List:\n");
print_list(sorted_list);
delete_list(my_list);
delete_list(sorted_list);
}
The segmentation fault is clear to me, you are using an uninitialized pointer here
if(temp == NULL || temp->value < newNode->value)
// ^
Or ANY OTHER newNode's dereference anywhere, because newNode is never initialized in your code.
If temp == NULL, and you didn't initialize newNode yet then undefined behavior.
Adding a node to a list while preserving order is easy,
Create the new node
If succeeded creating it, traverse the list until the next node is greater|smaller (depending on the ordering that you desire) than the new node.
When you find it, link current's node next to the new node and the next node should be new node's next.
And that is all.
I need some help.
I have this homework assignment due on Wednesday and the only thing I haven't been able to do is reverse my linked list. I have literally been working on this all day.
My professor hasn't told us any way to do this and doesn't allow us to email him questions so I'm kind of stuck.
He wants us to accomplish this by using nested while loops and pointers called front & back, and newhead.
Below is my code. Let me know if you have any questions and thanks in advance.
NOTE: Code is compiled in Code::Blocks using the GNU compiler.
#include <stdio.h>
#include <stdlib.h>
typedef struct node {
int random_number;
struct node *next;
} Node;
typedef Node *Nodeptr;
void printout(Nodeptr);
void sum(Nodeptr);
void reverse(Nodeptr);
int main() {
Nodeptr head = NULL;
if ((head = malloc(sizeof(Node))) == NULL)
return 0;
head->random_number = rand() % 50 + 50;
head->next = NULL;
Nodeptr here = head;
Nodeptr newnode = NULL;
int n;
for (n = 0; n < 10; n++) {
if ((newnode = malloc(sizeof(Node))) == NULL)
return 0;
newnode->random_number = rand() % 50 + 50;
newnode->next = NULL;
here->next = newnode;
here = here->next;
}
printout(head);
sum(head);
reverse(&head);
printout(head);
return 0;
}
void printout(Nodeptr head) {
Nodeptr aux = head;
int n = 0;
while (aux != NULL) {
printf("The value of node no. %d is %d \n", n, aux->random_number);
aux = aux->next;
n++;
}
}
void sum(Nodeptr head) {
Nodeptr aux = head;
int n = 0, sum = 0;
while (aux != NULL) {
sum += aux->random_number;
aux = aux->next;
n++;
}
printf("The sum total of all nodes in this list is %d\n", sum);
}
void reverse(Nodeptr head) {
Nodeptr newhead = head;
Nodeptr back = NULL;
Nodeptr front = NULL;
while (back != NULL) {
front->next = back;
back = NULL;
front = head->next;
back = head;
while (front != NULL) {
front = newhead->next;
newhead->next = back;
back = newhead;
}
newhead = head;
}
}
If you reverse a linked list:
A -> B -> C -> D -> E (odd numbered case)
E -> D -> C -> B -> A
A -> B -> C -> D (even numbered case)
D -> C -> B -> A
Do you see how the items have changed place? In the odd numbered case, A swapped places with E, B with D and C didn't move.
Now do you have some idea how to do it via a loop? The outer loop goes from the start of the list to the half-way point, the inner loop locates the matching item to swap them.
Definitely not the most efficient way to reverse a linked list, but I guess it's just a way to get you think more about the data structure.
The reverse() you posted didn't make sense, because the pointer values are incorrect. With back initialized to NULL, the while loop will not execute at all.
I am not sure what API you teacher want you to use for reverse:
The simplest one would take a Node * and return the new head pointer. You would invoke it from main as head = reverse(head);
Here is a simple implementation of this approach:
Node *reverse(Node *head) {
Node *front = head;
Node *newhead = NULL;
while (front) {
Node *back = front->next;
front->next = newhead;
newhead = front;
front = back;
}
return newhead;
}
An alternative API would have reverse take a pointer to the head pointer, hence a Node **, and update that to point to the reversed list.
Here is how it works:
void reverse(Node **headp) {
Node *front = *headp;
Node *newhead = NULL;
while (front) {
Node *back = front->next;
front->next = newhead;
newhead = front;
front = back;
}
*headp = newhead;
}
Note that you do not need nested loops.
Note also that you should not hide pointers behind typedefs, it is bad practice, error prone and creates confusion for both the next reader and the original author.
so I want to add inbetween two nodes of a linked list a new node whose data field basically contains the sum of the the previous and the next node. I can't understand why once I enter the while loop I can't get out of it. Any suggestions? Thank you.
Here's my code:
void modify_list (node *head) {
nodo *it = head;
nodo *prev = NULL;
int n_prev = 0;
int n_next = 0;
int sum = 0;
it = it->next;
prev = it;
while (it->next != NULL) {
it->data = n_next;
prev->data = n_prev;
sum = n_next + n_prev;
node *new;
new = malloc(sizeof(node));
if (new == NULL) {
printf("Error.\n");
return;
}
memset(nuovo, 0, sizeof(node));
new->data = sum;
prev->next = new;
new->next = it;
sum = 0;
prev = it;
it = it->next;
}
}
When you start the iteration, you are using:
it = it->next;
prev = it;
it and prev are pointing to the same node. A little while later, you are using:
prev->next = new;
which is the same as:
it->next = new;
That means it->next points to the new node. That means, you never really go past the newly created nodes.
You can fix this by using:
prev = it;
it = it->next;
before the start of the while loop.
I would make that more robust by using:
prev = it;
if ( it != NULL )
{
it = it->next;
}
At this time, it could be NULL. Change the conditional in the while statement to:
while (it != NULL) {
May I first suggest breaking your code up in smaller parts
Have a function that inserts a new object
For a singly linked list, this should insert after:
void InsertAfter( Node* n, DATA data )
{
Node* newnode = malloc(sizeof(Node));
newnode->data = data;
newnode->next = n->next;
n->next = newnode;
}
Then you have a function to find the insert-point
It could be for example
Node* FindLastSmaller( Node* n, DATA data )
{
while(true)
{
if( ! n->next ) return n;
if( n->next->data > data ) return n;
n = n->next;
}
}
Then they become easy to combine:
void InsertSorted( Node* n, DATA data )
{
Node* inspos = FindLastSmaller(n,data);
InsertAfter(inspos,data);
}
You can avoid adding special-cases for empty list, if head always
exists, and contains no data. (its a dummy node)
As the title implies. Deleting the first node in the linked list works like a charm. It's those other dang nodes! Ok, so here is my code. I think I am deleting properly, but I am not linking correctly.
Here is what the structs and typedefs look like:
typedef struct List *ListP;
typedef struct Entry *EntryP;
typedef char *ListItemP;
struct List
{
int sizeL;
struct Entry *head;
};
struct Entry
{
ListItemP content;
struct Entry *next;
int sizeL;
};
The way that the removeItemList function works in main.c is is by passing a list pointer (ListP thisList) and a string (ListItemP thisItem). Once the parameters have been passed, the function searches for the same string as a node in the list (via strcmp()) and when it finds it removes it. NewEntry initialized Entry struct and has an input that passes a character to newEntry->content. Anyways, here is the function :
void removeItemList(ListP thisList, ListItemP thisItem)
{
EntryP temp = newEntry(0x00);
EntryP temp2 = newEntry(0x00);
temp->next = thisList->head;
temp2->next = thisList->head;
if (strcmp(temp->next->content, thisItem) == 0)
{
thisList->head = temp->next->next;
}
else {
while(temp->next != 0x00)
{
if(strcmp(temp->next->content,thisItem) == 0) {
break;
}
temp->next = temp->next->next;
temp->sizeL++;
}
if (temp->next == 0x00) {
}
else {
int i = 0;
for(i = 0; i < temp->sizeL - 1 ; i++)
{
temp2->next = temp2->next->next;
printf("%s \n", temp2->content);
}
temp2->next = temp->next->next;
free(temp2->next);
}
}
thisList->sizeL--;
}
I think that the node before the node being removed winds up being pointed to null. I am having trouble figuring out how to fix that, though. I guess that's why I'm here! Anything will be greatly appreciated, thank you very much!
EDIT: UPDATED CODE, PLUS DIPLAY LIST CODE
Updated removeItemList()
void removeItemList(ListP thisList, ListItemP thisItem)
{
EntryP current = newEntry(0x00);
EntryP prev = newEntry(0x00);
prev = 0x00;
current = thisList->head;
if (strcmp(current->content, thisItem) == 0)
{
thisList->head = current->next->next;
}
else {
while (current->next != 0x00)
{
prev = current;
current = current->next;
if (strcmp(current->content, thisItem) == 0)
{
prev->next = current->next;
free(current);
}
}
}
}
DisplayList():
void displayList(ListP thisList)
{
EntryP temp = newEntry(0x00);
temp->next = thisList->head;
while(temp->next != 0x00)
{
printf("%s \n", temp->next->content);
temp->next = temp->next->next;
}
free(temp);
}
If I were to just use printf() statements, I can access everything just fine and the node seems deleted. However, if I'm trying to print them with displayList(), I get a segfault after printing the node before the one being deleted. So it seems as if I'm not linking the nodes correctly.
For deleting any intermediate nodes, maintain two pointers to the list, prev and cur. Initialize prev to null and cur to the head of the list. Now traverse the list until you meet the node to be deleted. Before moving to the next node in the analysis, reassign prev to cur and cur to cur->next.
When the required node is reached, do
prev->next = cur->next;
free(cur);
return;// If necessary.
Entire pseudocode:
prev = null;
cur = list->head;
while(cur!=null)
{
if(//This is the node to be deleted)
{
prev->next = cur->next;
free(cur);
return;
}
prev = cur;
cur = cur->next;
}
//Node not found case
Now integrate this scenario into your code, and you should be fine. Before this, just check explicitly for the first node though, as this won't fit into the above use case.
UPDATE: I noticed a few bugs in your function DisplayList(). Why are you analysing with temp->next during traversal? Seems like a roundabout method to me. Just analyse with temp.
void displayList(ListP thisList)
{
EntryP temp = thisList->head;
while(temp!= 0x00)
{
printf("%s \n", temp->content);
temp = temp->next;
}
}
And why were you freeing the temp node during the list display? If you just want to display the list contents, freeing the node doesn't make any sense acc. to me.