Delete elements from linked list - c

The function not working properly it's deleating only the id_capt and changing the value of another to zero...
Besides I want to do verification that the sensor does belong to the list but it's not working
void suppression_capt(Liste* liste)//id donner par utilisateur a modifier
{
float new_longitude,new_latitude;//vals a modifier
char id_capt_user[10];
Element *courant = liste->premier;
Element *precedent =courant;
printf("donner id_capt= ");
scanf("%s",id_capt_user);
while(courant != NULL)
{
if(strcmp(courant->capt.id_capt,id_capt_user)==0)
{
precedent=courant->suivant;
free(courant);
}
courant=courant->suivant;
}
printf("\n");
}
Besides I want to do verification that the sensor does belong to the list but it's not working
/*do
{
printf("donner id_capt= ");
scanf("%s",id_capt_user); //verification du capteur
courant=courant->suivant;
}while(strcmp(courant->capt.id_capt,id_capt_user)!=0);*/
and here is the struct that I used
typedef struct//valeur d'une cellule/noeud
{
char id_capt[10];
float longitude;
float latitude;
}capt_hum;
typedef struct//liste chainee
{
capt_hum capt;
struct Element* suivant;
struct Element* precedent;
}Element;

You should note that you are accessing a pointer which you have already freed
if(strcmp(courant->capt.id_capt,id_capt_user)==0)
{
precedent=courant->suivant;
free(courant);
}
courant=courant->suivant;
As for deleting an element from a linked list freeing it is not enough as you need to update the element’s neighbors as well.
Say you have a list as follows:
A <-> B <-> C
And you wish to remove B, you will also need to update A and C to point to each other
A <-> C
if(strcmp(courant->capt.id_capt,id_capt_user)==0)
{
temp = courant->suivant;
precedent=courant->precedent;
free(courant);
precedent->suivant = temp;
temp->precedent = precedent;
courant = precedent; //perhaps replace with break
}
courant=courant->suivant;
With this implementation you will iterate the entire list an remove any node that contains the string you’ve entered.
You could replace the commented line with “break” if you wish to stop seeking once you’ve found the node to delete.
You should add some check for the cases where the node to remove is either the first or the last so you wont accidentally try to assign them when the pointers are NULL or garbage.

after looking and trying because I'm still new to doubly linked list
this program worked
void supprimer_capt(Liste **list) {
Element* tmp = *list;
Element* prev = NULL;
char id_capt_user[10];
printf("donner id_capt= ");
scanf("%s",id_capt_user);
while (tmp != NULL)
{
if (strcmp(tmp->capt.id_capt,id_capt_user)==0)
{
if (prev == NULL)
{
tmp = tmp->suivant;
free(*list);
*list = tmp;
} else {
prev->suivant = tmp->suivant;
free(tmp);
tmp = prev->suivant;
}
} else {
prev = tmp;
tmp = tmp->suivant;
}
}
}
I know I there must be two pointers prev and next and thanx to this function I have a better understanding and the link sent by Mr.Roberet

Related

Updating linked-list by pointer inside a function

I'm missing with linked-list and trying to make a function which gonna take of all the odd numbers out of the link and make a new linked-list with them.
The point is that I dont understand how to update the original list by pointer to the function, actually what I made so far is making a new list with the odd numbers but I dont really understand how to "delete" them from the original list and link all the rest togther, then send it back to the main.
Node *build_odd_list(Node *oldlst, Node *newlst) {
Node *temp, *curheadNew;
temp = (Node*)malloc(sizeof(Node));
if (oldlst->value % 2 != 0) {
temp->next = NULL;
temp->value = oldlst->value;
newlst = temp;
curheadNew = newlst;
oldlst = oldlst->next;
printf("Passed %d\n", curheadNew->value);
}
else {
oldlst = oldlst->next;
}
while (oldlst) {
if (oldlst->value % 2 != 0) {
temp = (Node*)malloc(sizeof(Node));
temp->value = oldlst->value;
temp->next = NULL;
curheadNew->next = temp;
curheadNew = curheadNew->next;
oldlst = oldlst->next;
printf("Passed %d\n", curheadNew->value);
}
else {
oldlst = oldlst->next;
}
}
return newlst;
}
Thanks a lot!
Since you need to return a new list containing the odd numbers, and modify the original list due to removal of the odd numbers, you need to pass two values back to the caller: a pointer to the first element of the updated original list, and a pointer to the first element of the "odd numbers" list.
Since you need to pass the original list to the function anyway, the simplest option for the function is to:
pass a pointer to a pointer to the first element of the original list;
modify the original list via the pointer;
return a pointer to the first element of the "odd numbers" list extracted from the original list.
There is no need to allocate any new elements for the "odd numbers" list as the odd number elements can be moved from one list to the other.
It is worth learning the "pointer to a pointer" trick as it is a common way of manipulating list pointers.
Here is an example program to illustrate the above method. Pay particular attention to the extract_odd_list() function and the call to that function from main().
#include <stdio.h>
#include <stdlib.h>
typedef struct _Node {
int value;
struct _Node *next;
} Node;
/* Move odd numbers in *list to returned list. */
Node *extract_odd_list(Node **list) {
Node *oddstart = NULL; /* start of returned list */
Node **oddend = &oddstart; /* pointer to final link of returned list */
while (*list) {
if ((*list)->value % 2 != 0) {
/* Current element of original *list is odd. */
/* Move original *list element to end of returned list. */
*oddend = *list;
/* Bypass moved element in original list. */
*list = (*list)->next;
/* Update pointer to final link of returned list. */
oddend = &(*oddend)->next;
}
else {
/* Current element of original *list is even. */
/* Skip to next element of original *list. */
list = &(*list)->next;
}
}
/* Terminate the returned list. */
*oddend = NULL;
/* And return it. */
return oddstart;
}
void *printlist(Node *list) {
while (list) {
printf(" %d", list->value);
list = list->next;
}
}
int main(void) {
int i;
Node *list = NULL;
Node *end = NULL;
Node *oddlist;
Node *temp;
/* Construct a list containing odd and even numbers. */
for (i = 1; i <= 10; i++) {
temp = malloc(sizeof(*temp));
temp->value = i;
if (end == NULL) {
list = temp;
}
else {
end->next = temp;
}
end = temp;
}
end->next = NULL;
printf("Original list:");
printlist(list);
printf("\n");
/* Move the "odd number" elements from the original list to a new list. */
oddlist = extract_odd_list(&list);
printf("Updated list:");
printlist(list);
printf("\n");
printf("Odd list:");
printlist(oddlist);
printf("\n");
return 0;
}

Freeing double linked list I created

I tried to free the linked list I created , but I failed.
An extension on the previous question I asked "Merge double linked list", it is OK if you don't check it or know nothing about it.
I created two double linked list, and I merged them, and after that, I want to free them all. So I wrote the delete_list() function.
But eventually, I failed, the error is "error for object 0x100404110: pointer being freed was not allocated".
If I only free the first list l, the code works. But if I tried to free all or two, the code crushed.
Can anyone help me with it? Thanks!!
#include <stdio.h>
#include<stdlib.h>
typedef struct Node
{
struct Node* prior;
struct Node* next;
int value;
}Node,*list;
list create_list()
{
list head = (list)malloc(sizeof(Node));
if(!head) exit(-1);
list tail;
tail=head;
printf("Please enter the length of double linked list:\n");
int len;
scanf("%d",&len);
for(int i=0;i<len;i++)
{
list new = (list)malloc(sizeof(Node));
if(!new) exit(-1);
new->next=NULL;
printf("Please enter the value of node:\n");
int val;
scanf("%d",&val);
new->value=val;
tail->next = new;
new->prior=tail;
tail=new;
}
return head;
}
list merge_list(list a,list b)//合并两个非递减双向链表
{
if(a==NULL||b==NULL) exit(-1);
list p=(list)malloc(sizeof(Node));
list l=p;
while(a&&b)
{
if(a->value<=b->value)
{
p->next = a;
a->prior=p;
p=a;
a=a->next;
}
else
{
p->next = b;
b->prior=p;
p=b;
b=b->next;
}
}
if(a!=NULL)
{
p->next=a;
a->prior=p;
}
if(b!=NULL)
{
p->next=b;
b->prior=p;
}
return l;
}
int delete_List(list l)
{
if(l==NULL)
{
printf("List is empty!");
exit(-1);
}
list temp;
while(l)
{
temp = l->next;
free(l);
l=NULL;
l=temp;
}
return 1;
}
int main() {
list l = create_list();
l=l->next;//throw away the empty node
list m = create_list();
m=m->next;//throw away the empty node
list n =merge_list(l,m);
n=n->next; //throw away the empty node
delete_List(l);
delete_List(m);
delete_List(n);
return 0;
}
NO error.
I believe your problem lies in calling delete_list on the component lists that you passed to your merge_list function.
If I understand your code correctly, a list is really just a pointer to the first node of the linked list. Your create_list allocates the nodes, and returns the address of the first, which you then discard for whatever reason, resulting in a pointer to the second allocated node.
Something like this:
list l = pointer to [1] -> [2] -> [3] ...
list m = pointer to [5] -> [10] -> [15] ...
Your merge_list performs a merge sort of the two lists, using the same nodes by changing the next/prev pointers.
while(a&&b)
{
if(a->value<=b->value)
{
p->next = a;
a->prior=p;
p=a;
a=a->next;
This means that list pointer l and list pointer m and list pointer n (the merged list) are all pointing to the same nodes. When you do list n = merge_list(l,m) the result is something like:
list n = pointer to [1] -> [2] -> [3] -> [5] -> [10] ...
list l = pointer to ^
list m = pointer to 5 ...................^
(The 'l' and 'm' pointers are not changing, but the nodes that they point to are being modified by the merge function.)
When you try to free the list nodes in your delete function, the first call to delete list 'l' will work. The call to delete list 'm' will either fail immediately (if the first node of 'm' was greater than the first node of 'l', as in my example) or free some nodes and then fail. The delete of 'n' will fail since all the nodes making up 'n' are deleted in the calls to delete 'l' and 'm'.
You can fix this in several ways. The easiest is simply to reset the l and m list pointer to NULL when you call the merge, since in your system merging the two lists "consumes" them, and thus ownership transfers from the parameters to the result.
list n = merge_list(l, m); l = m = NULL;
Another way would be for the merge function to create duplicate nodes, meaning that merge_list would actually produce copies of the two lists, allowing ownership of the parameters to be maintained by the caller.
list n = merge_list(l, m);
// now n, l, m, all exist and are separate
A final solution would be for you to create a true "list" object that sits between the caller and the node objects. This object could be modified to reflect either reality, but it would be separate, and so would not get overwritten during merge operations, etc. (I don't recommend this, btw. It's formal, but inefficient.)
The obvious answer to why you can't free the 3 lists is because you don't have 3 lists. Your function merge_list is doing exactly what the name (sort of) suggests. It is taking the 2 lists and merging them into 1 list. So you don't have to free the 2 original lists, you only need to free the merged one.
the function: create_list() has several problems including not checking for errors and not properly handling the insertion of the new node at the front of the list and not handling the first entry into a linked list correctly.
The formatting/style of the code leaves a lot to be desired.
The single character parameter and local variable names are meaningless Such names should indicate content or usage
The delete_list() should not be returning anything as there is nothing left to return. So the signature changed to:
void delete_List( Node *list )
should not typedef a pointer as that just adds confusion to the code.
The following proposed code fixes the above problems and formats the code for readability
Caveat: it has not been tested yet
struct NODE
{
struct NODE* prior;
struct NODE* next;
int value;
};
typedef struct NODE Node;
Node * create_list()
{
Node * head = NULL;
printf("Please enter the length of double linked list:\n");
int len;
if( scanf("%d",&len) != 1 )
{
fprintf( stderr, "scanf for length of list failed\n" );
return NULL;
}
for( int i=0; i<len; i++ )
{
Node * newNode = malloc(sizeof(Node));
if ( !newNode )
{
perror( "malloc for list nodefailed" );
// cleanup here
exit( EXIT_FAILURE );
}
if ( !head )
{ // then first entry into linked list
newNode->next = NULL;
newNode->prior = NULL;
}
else
{
//insert node at front of list
newNode->next = head;
head->prior = newNode;
newNode->prior = NULL;
}
printf("Please enter the value of node:\n");
int val;
if( scanf("%d",&val) != 1 )
{
fprintf( stderr, "scanf for node value failed\n" );
// clean up here
exit( EXIT_FAILURE );
}
newNode->value = val;
head = newNode;
}
return head;
}
Node * merge_list( Node *left, Node *right )//合并两个非递减双向链表
{
if( !left || !right)
exit(-1);
Node * workNode = NULL;
Node * returnNode = NULL;
while ( left && right )
{
if( !workNode )
{ // then first loop
if( left->value <= right->value )
{
workNode = left;
left = left->next;
}
else
{
workNode = right;
right = right->next;
}
// remember address of beginning of merged list
returnNode = workNode;
}
else if( left->value <= right->value )
{
workNode->next = left;
left->prior = workNode;
workNode = left;
left = left->next;
}
else
{
workNode->next = right;
right->prior = workNode;
workNode = right;
right = right->next;
}
}
// if more entries in left
if( left )
{
workNode->next = left;
}
else if( right )
{
workNode->next = right;
}
return returnNode;
}
void delete_List( Node *list )
{
if(list==NULL)
{
printf("List is empty!");
exit(-1);
}
Node * temp;
while(list)
{
temp = list->next;
free( list );
list = temp;
}
}

Segmentation fault while creating a linked list

I am writing a small program which stores data and key inside a linked list structure, and retrieves data based on a key from the user. The program also checks whether it is a unique key and if it so it stores the data by creating a node at the front of the list. But the below code throws segmentation fault all the time.
#include<stdlib.h>
/* Node having data, unique key, and next */.
struct node
{
int data;
int key;
struct node *next;
}*list='\0',*p;
/* Create a node at the front */
void storeData(int data_x,int key_x)
{
int check_key;
position *nn; //nn specifies newnode
nn=(position)malloc(sizeof(struct node));
/* Segmentation Fault occurs here */
if(list->next==NULL)
{
nn->next=list->next;
nn->data = data_x;
nn->key = key_x;
list->next = nn;
}
else
{
check_key=checkUniqueKey(key_x);
if(check_key != FALSE)
{
printf("The entered key is not unique");
}
else
{
nn->data = data_x;
nn->key = key_x;
nn->next=list->next;
list->next=nn;
}
}
}
/* Retreive data based on a key */
int retreiveData(int key_find)
{
int ret_data = NULL;
p=list->next;
while(p->next != NULL)
{
if(p->key == key_find)
{
ret_data = p->data;
break;
}
p=p->next;
}
return(ret_data);
}
/* Checks whether user key is unique */
int checkUniqueKey(int key_x)
{
int key_check = FALSE;
p=list->next;
while(p->next != NULL)
{
if(p->key == key_x)
{
key_check = TRUE;
break;
}
p=p->next;
}
return(key_check);
}
The segmentation fault occurs in the storeData function after the dynamic allocation.
There are some problems in your code:
your list handling is flawed: you always dereference the global pointer list, even before any list items are created. You should instead test if the list is empty by comparing list to NULL.
type position is not defined. Avoid hiding pointers behind typedefs, this is a great cause of confusion, which explains your mishandling of list pointers.
avoid defining a global variable with the name p, which is unneeded anyway. Define p as a local variable in the functions that use it.
NULL is the null pointer, 0 a zero integer value and \0 the null byte at the end of a C string. All 3 evaluate to 0 but are not always interchangeable.
For better portability and readability, use the appropriate one for each case.
Here is an improved version:
#include <stdio.h>
#include <stdlib.h>
/* Node having data, unique key, and next */.
struct node {
int data;
int key;
struct node *next;
} *list;
/* Create a node at the front */
void storeData(int data_x, int key_x) {
if (checkUniqueKey(key_x)) {
printf("The entered key is not unique\n");
} else {
/* add a new node to the list */
struct node *nn = malloc(sizeof(struct node));
if (nn == NULL) {
printf("Cannot allocate memory for node\n");
return;
}
nn->data = data_x;
nn->key = key_x;
nn->next = list;
list = nn;
}
}
/* Retrieve data based on a key */
int retrieveData(int key_find) {
struct node *p;
int ret_data = 0;
for (p = list; p != NULL; p = p->next) {
if (p->key == key_find) {
ret_data = p->data;
break;
}
}
return ret_data;
}
/* Checks whether user key is unique */
int checkUniqueKey(int key_x) {
struct node *p;
int key_check = FALSE;
for (p = list; p != NULL; p = p->next) {
if (p->key == key_x) {
key_check = TRUE;
break;
}
}
return key_check;
}
You try to cast your address on a position structure instead of a position*
nn=(position)malloc(sizeof(struct node));
Compile your code with gcc flags -Wextra and -Wall to prevent this kind of issue.
Moreover I don't know is it is a mistake but malloc a size of struct node and your nn variable is a pointer on position.
When you initialized your list pointer you set it to NULL(as '\0'), when the program accesses address 0x00 it goes out of its boundaries and the operating system kills the process.
To avoid the segfault you can have "list" of non pointer type thus allocating on stack, when you want to access list as pointer you can do &list. Another solution would involve having variable on stack "root_node" and initialize list pointer as list = &root_node.

Adding node in Linked List in a specific position in C

I'm trying to add a node to a linked list. The idea is to pass in the pointer, see where new node will go to through a ranked order, in this case G, then D, then M, then S.
Yet, when I compile and run, I'm not actually generating a linked list (this has already been done in the main). I'm more than certain that there's something wrong with my addp() function. Is it that I should pass in double pointers instead?
Sorry for being rather unprofessional and clueless. I'm not the strongest of coders.
Any help would be helpful.
I have attached my method which I have gone through so many times.
typedef struct node {
char fname[1024];
char lname[1024];
char pos;
int val;
int rank;
struct node * next;
} player;
struct node* addp (player* newnode, struct node* list){
player* templist = list;
player* templist1;
// if the list is non empty.
if (list!=NULL){
if(newnode->pos == GOALKEEPER){ //insert if G.
newnode->next = list;
}
if(newnode->pos == DEFENDER){// after G bef M.
// iterate through templist.
while (templist->next != NULL && (templist->next)->rank < 1) { // go to end of G.
// when the list isn't empty next node rank is less than one, keep going
templist = templist -> next;
}
// when finally rank == or > 1, then add newnode.
templist1 = templist->next;
templist->next = newnode;
newnode->next = templist1;
}
if(newnode->pos == MIDFIELDER){ //after G and M but before S
while (templist->next != NULL && (templist->next)->rank <2 && (templist->next)->rank> 2){
templist = templist -> next;
}
// when stopped, then add newnode.
templist1 = templist->next;
templist->next = newnode;
newnode->next = templist1;
}
if(newnode->pos == STRIKER){ // at the end.
while (templist->next != NULL && (templist->next)->rank <3){
templist = templist -> next;
}
templist1 = templist->next;
templist->next = newnode;
newnode->next = templist1;
}
return list;
printf("player added");
}
// if list is empty
else{
newnode->next = list;
return 0;
}
}
The following is the list function I've come up with. It keeps saying that my linked list is empty. Maybe it's something wrong with this function.
int print(struct player* list){
// create temp list so non modify origin.
struct player* temp = list;
if (list == NULL && temp == NULL)
printf("linked list is empty");
while (temp != NULL){
printf("%s \n", temp->lname);
printf("%s \n", temp->fname);
printf("%c \n", temp->pos);
printf("d \n", temp->val);
temp = temp->next;
}
return 0;
}
Without knowing the player typedef this is hard to analyze, but I think you can make it much easier on yourself by simplifying the signature of the function to only use player.
void addp(player* newnode, player* firstnode)
The return is unnecessary since you're just returning the 2nd argument, which the caller already has. The 2nd argument should be a pointer to a player node, which is the first element in your linked list. If you can call the function without the compiler complaining about implicitly casting pointers then I don't see anything wrong with your algorithm, although it could certainly be simplified.
Ok so what I understood is that your player structure contains a variable pos that will indicate in which place insert the player in the list. Am I right ?
In that case the best thing you can do is to sorted the list by the rank variable. Then modify your pos variable (in the player structure) to match with the rank variable of your list.
Then you will just have to add it with a classic "add in sorted list" function : C++ Add to linked list in sorted orderenter link description here

Deleting Nodes in a Linked List

After a lot of effort, I've managed to piece together a function that deletes some node from my linked list. But, out of sheer interest, I would like to find out how you can go about deleting the first node from the list, i.e. the head.
My program asks for a letter to delete, so for example.
Hello is stored in the list, the user inputs H for deletion, so that now the list is ello
At the moment with my code, the program crashes obviously as if H is deleted, there is no head, and the program doesn't know where to go to look for the list.
Below is my current implementation, any clues or hints on how to modify this code( I would like to keep it similar to how I have) to allow Head Node Deletion would be much appreciated!.
EDIT: In response to below
FullList DeleteNode(FullList temp, char c) {
FullList remember;
FullList ptr;
while (temp.head->c != c) {
remember.head = temp.head;
temp.head = temp.head->next;
}
ptr.head = temp.head->next;
free(temp.head);
remember.head->next = ptr.head;
return temp;
}
int main(void) {
FullList List;
char c, s;
List.head = NULL;
while ((c=getchar()) != '.') {
List = addToEnd(List, c);
}
scanf(" %c", &s);
List = DeleteNode(List, s);
while (List.head != NULL) {
printf("%c", List.head->c);
List.head = List.head->next;
}
return 0;
}
typedef struct List {
char c;
struct List *next;
}List;
typedef struct {
List *head;
List *tail;
}FullList;
List *insertList(char c, List *t1) {
List *t = (List*)calloc(1, sizeof(List));
t->c = c ;
t->next = t1;
return t;
}
FullList addToEnd(FullList c, char element) {
if (c.head == NULL) {
c.head = c.tail = insertList(element, NULL);
}else {
c.tail->next = insertList(element, NULL);
c.tail = c.tail->next;
}
return c;
}
void DeleteNode(FullList temp, char c) {
FullList remember;
FullList ptr;
while (temp.head->c != c) {
remember.head = temp.head;
temp.head = temp.head->next;
}
ptr.head = temp.head->next;
free(temp.head);
remember.head->next = ptr.head;
}
int main(void) {
FullList List;
char c, s;
List.head = NULL;
while ((c=getchar()) != '.') {
List = addToEnd(List, c);
}
scanf(" %c", &s);
DeleteNode(List, s);
while (List.head != NULL) {
printf("%c", List.head->c);
List.head = List.head->next;
}
return 0;
}
You can't do it without changing your existing code.
You're passing your FullList struct to your DeleteNode() function. This means that any changes to that struct are not visible back in main - the function is getting a copy of it.
You would need to change DeleteNode() to accept a pointer:
void DeleteNode(FullList *temp, char c)
Then when calling it main() you would do:
DeleteNode(&List, s);
By doing this, you can change the value of temp->head in your function and it will be visible back in main()
temp->head = temp->head->next;
Edit: The logic you'll need is:
Check to see if temp->head->c == c
If yes, replace temp->head with temp->head->next
else assign temp->head to a temp pointer *previous. Assign temp->head->next to a pointer *current. Loop through the list, moving both pointers. When you find a match in current->c, assign current->next to previous->next and free() the current node.
The way it is now, inside DeleteNode, when you change the argument, it only changes the local variable, not the one outside the function.
You either have to pass the FullList to DeleteNode by pointer so that modifications done to it will be visible to the caller, or modify a local one and return it, and the caller must assign the returned FullList to its list.
Either way, the changes made by DeleteNode must become visible to the caller.

Resources