I'm trying to implement a function that deletes nodes from a linked list. So far, I can delete just the first node of the list(3).
I tried to go to the for loop from delete, I thought that the memory is not well allocated, I have been struggling for a few days and I don't understand, please help me a little, it's the topic I received from college.
#include <stdio.h>
#include <stdlib.h>
typedef struct nod
{
int key;
struct nod *urm;
} NOD;
NOD *first=0,*last=0;
void add(int x)
{
NOD *p=(NOD*)malloc(sizeof(NOD));
p->key=x;
p->urm=0;
if(0==first)
{
first=p;
last=p;
}
else{
last->urm=p;
last=p;
}
}
void delete(int x)
{
NOD *q,*p;
if(first->key==x)
{
p=first;
first=first->urm;
free(p);
}
else{
for(p=q=first;p=0;q=p,p=p->urm)
{
if(p->key==x)
{
q->urm=p->urm;
if(p==last)
{
last=q;
}
free(p);
}
}
}
}
void show()
{
for(NOD *p=first;p!=0;p=p->urm)
{
printf("%d ",p->key);
}
printf("\n");
}
int main()
{
add(3);
add(1);
add(2);
add(5);
show();
delete(2);
show();
return 0;
}
For starters the code you showed is not a C++ code. It is a C code.
It is a bad idea to define global variables like first and last and when functions depend on global variables. In this case you can not create more than one list in a program.
As for the function delete then in general it has undefined behavior. It can be called for an empty list.
Moreover in this ;loop
for(p=q=first;p=0;q=p,p=p->urm)
there is a typo in the condition expression. You are using the assignment operator instead of the comparison operator.
And you function ignore the case when the list contains only one node because in this case it does not update the last node.
Nevertheless using your approach the function delete can look the following way.
void delete(int x)
{
if ( first )
{
if ( first->key == x )
{
NOD *tmp = first;
first = first->urm;
free( tmp );
if ( first == NULL ) last = NULL;
}
else
{
NOD *p = first;
while ( p->urm != NULL && p->urm->key != x )
{
p = p->urm;
}
if ( p->urm != NULL )
{
NOD *tmp = p->urm;
p->urm = p->urm->urm;
free( tmp );
if ( p->urm == NULL ) last = p;
}
}
}
}
Here is a demonstrative program.
#include <stdio.h>
#include <stdlib.h>
typedef struct nod
{
int key;
struct nod *urm;
} NOD;
NOD *first=0,*last=0;
void add(int x)
{
NOD *p=(NOD*)malloc(sizeof(NOD));
p->key=x;
p->urm=0;
if(0==first)
{
first=p;
last=p;
}
else{
last->urm=p;
last=p;
}
}
void delete(int x)
{
if ( first )
{
if ( first->key == x )
{
NOD *tmp = first;
first = first->urm;
free( tmp );
if ( first == NULL ) last = NULL;
}
else
{
NOD *p = first;
while ( p->urm != NULL && p->urm->key != x )
{
p = p->urm;
}
if ( p->urm != NULL )
{
NOD *tmp = p->urm;
p->urm = p->urm->urm;
free( tmp );
if ( p->urm == NULL ) last = p;
}
}
}
}
void show()
{
for(NOD *p=first;p!=0;p=p->urm)
{
printf("%d ",p->key);
}
printf("\n");
}
int main()
{
add(10);
add(20);
add(30);
add(40);
show();
delete(30);
show();
add( 50 );
add( 60 );
add( 70 );
add( 80 );
show();
delete(80);
show();
return 0;
}
Its output is
10 20 30 40
10 20 40
10 20 40 50 60 70 80
10 20 40 50 60 70
You can greatly simplify deleting a node from your list by using both a pointer-to-pointer to NOD and a pointer-to NOD to iterate over the list. This allows you to set the node at the current address to the node->urm eliminating the need to keep track of the previous node in the list, e.g.
/** delete node with key v from list (for loop) */
void delete (int v)
{
NOD **ppn = &first; /* pointer to pointer to first*/
NOD *pn = first; /* pointer to first */
for (; pn; ppn = &pn->urm, pn = pn->urm) {
if (pn->key == v) {
*ppn = pn->urm; /* set node at address to next node */
free (pn); /* free deleted node */
break;
}
}
}
See Linus on Understanding Pointers for further discussion on the advantages of using the address of a node in addition to a pointer to node.
I think your for loop condition is incorrect inside delete functions:
for(q=first, p=first->urm; p!=0; q=p, p=p->urm)
just change the condition, then it should work.
Related
I have a linked list of a struct,
here is my struct:
typedef struct avion
{
int code;
int capacite;
char etat[1];
int date;
int nvols;
} avion;
typedef struct element *list;
typedef struct element
{
avion A;
struct element *svt;
} element;
I want to sort the linked list in ascending order according to the element of the struct "capacite".
here is the code of the function tri:
list *tri(list *L)
{
list *i,*j,*min;
avion x;
for (i=L; (*i)->svt != NULL; i=(*i)->svt)
{
min=i;
for (j=(*i)->svt; j != NULL; j=(*j)->svt)
{
if ((*j)->A.capacite < (*min)->A.capacite)
min=j;
}
if (min != i)
{
x=(*min)->A;
(*min)->A = (*i)->A;
(*i)->A = x;
}
}
return(L);
}
But i have the warning: assignement from incompatible pointer (in the two lines of the for loop: and i dont know how to fix it.
Is there any better way to sort my linked list according to this criterion?
For example in this for loop
for (i=L; (*i)->svt != NULL; i=(*i)->svt)
the variable i declared like
list *i
has the type struct element **. On the other hand the data member svt has the type struct element *. Thus this assignment
i=(*i)->svt
contains operands of different types and there is no implicit conversion from the type struct element * to the type struct element **.
Pay attention to that the function can invoke undefined behavior if it will be called for an empty list due to this expression
(*i)->svt != NULL;
Also this declaration of an array with one element
char etat[1];
does not make a great sense.
And introducing such an alias for a pointer like this
typedef struct element *list;
in general is not a good idea. It can only confuse readers of the code.
There is no need to pass to the function tri (that implements the selection sort) the pointer to the head node by reference through a pointer to it because the pointer itself is not being changed within the function.
The function can be declared and defined the following way as it is shown in the demonstrative program below.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct avion
{
int capacite;
} avion;
typedef struct element list;
typedef struct element
{
avion A;
struct element *svt;
} element;
int push_front( list **head, int capacite )
{
element *new_element = malloc( sizeof( element ) );
int success = new_element != NULL;
if ( success )
{
new_element->A.capacite = capacite;
new_element->svt = *head;
*head = new_element;
}
return success;
}
void display( const list *head )
{
for ( ; head != NULL; head = head->svt )
{
printf( "%d -> ", head->A.capacite );
}
puts( "null" );
}
void tri( list *head )
{
for ( ; head != NULL; head = head->svt )
{
element *min = head;
for ( element *current = head->svt; current != NULL; current = current->svt )
{
if ( current->A.capacite < min->A.capacite )
{
min = current;
}
}
if ( min != head )
{
avion tmp = min->A;
min->A = head->A;
head->A = tmp;
}
}
}
int main(void)
{
enum { N = 10 };
list *head = NULL;
srand( ( unsigned int )time( NULL ) );
for ( int i = 0; i < N; i++ )
{
push_front( &head, rand() % N );
}
display( head );
tri( head );
display( head );
return 0;
}
The program output might look for example the following way.
7 -> 1 -> 2 -> 6 -> 0 -> 9 -> 0 -> 9 -> 6 -> 0 -> null
0 -> 0 -> 0 -> 1 -> 2 -> 6 -> 6 -> 7 -> 9 -> 9 -> null
If to use your alias definition of the name list then the function can look as it is shown in this demonstrative program.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
typedef struct avion
{
int capacite;
} avion;
typedef struct element *list;
typedef struct element
{
avion A;
struct element *svt;
} element;
int push_front( list *head, int capacite )
{
element *new_element = malloc( sizeof( element ) );
int success = new_element != NULL;
if ( success )
{
new_element->A.capacite = capacite;
new_element->svt = *head;
*head = new_element;
}
return success;
}
void display( list head )
{
for ( ; head != NULL; head = head->svt )
{
printf( "%d -> ", head->A.capacite );
}
puts( "null" );
}
void tri( list head )
{
for ( ; head != NULL; head = head->svt )
{
element *min = head;
for ( element *current = head->svt; current != NULL; current = current->svt )
{
if ( current->A.capacite < min->A.capacite )
{
min = current;
}
}
if ( min != head )
{
avion tmp = min->A;
min->A = head->A;
head->A = tmp;
}
}
}
int main(void)
{
enum { N = 10 };
list head = NULL;
srand( ( unsigned int )time( NULL ) );
for ( int i = 0; i < N; i++ )
{
push_front( &head, rand() % N );
}
display( head );
tri( head );
display( head );
return 0;
}
Because of this
typedef struct element *list;
When you write
list *i
i isn't a pointer on an element but a pointer on a pointer of an element
I have problem with deleting elements from list
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 30
typedef struct elem{
char name[MAX];
int statistic;
int price;
struct elem *next;
struct elem *prev;
} shop;
I created function with search in list for a word defined in main and then if it finds it it keeps deleting 1st element until it finds the word and then it deletes selected word and makes next as first:
void delete_from_list(shop *first, char word[MAX], int* check)
{
shop *tmp= first;
while (tmp!=NULL && strcmp(tmp->name, word) != 0)
{
tmp = tmp->next;
}
if (tmp != NULL && strcmp(tmp->name, word)==0)
{
printf("FOUND!");
}
else
{
*check=1;
}
if (check==0)
{
while (strcmp(first->name, tmp->name)!=0)
{
first=first->next;
free(first->prev);
first->prev=NULL;
}
first=first->next;
free(first->prev);
first->prev=NULL;
}
}
void print_list(shop *first)
{
first=first->next;
if(first->name==NULL)
printf("There is nothing!!!\n");
while(first->next!=NULL){
printf("%20s",first->name);
printf("%20d \t\t",first->statistic);
printf("%d\n",first->price);
first=first->next;
}
}
I print the list and then take word.
main()
{
int check = 0;
print_list(first);
scanf("%s", word);
delete_from_list(first, word, &check);
if (check!=1)
{
print_list(first);
}
else
{
check=0;
}
}
The problem is that linked list doesn't change so probably I should add pointers but I have no idea how.
You have to pass pointer first by reference.
Also the function has a bug. The next element after the found element can be equal to NULL. In this case these statements
first=first->next;
free(first->prev);
^^^^^^^^^^^
first->prev=NULL;
^^^^^^^^^^^
result in undefined behaviour.
The function can be written the following way
void delete_from_list( shop **first, const char *word, int *check )
{
shop *tmp = *first;
while ( tmp!=NULL && strcmp( tmp->name, word ) != 0 )
{
tmp = tmp->next;
}
if ( tmp != NULL)
{
printf("FOUND!");
}
else
{
*check = 1;
}
if ( check == 0 )
{
tmp = tmp->next;
while ( *first != tmp )
{
shop *current = *first;
*first = ( *first )->next;
free( current );
}
if ( *first ) ( *first )->prev = NULL;
}
}
Also it is a bad design that the function relies on the value of check that is set in main. It would be better if the function itself set varaible check. In this case you could split the function into tow functions. The first one would search the target element and the second one wpuld delete all elements that satisfy the criteria if it is required.
I would define the function the following way
int delete_from_list( shop **first, const char *word )
{
shop *tmp = *first;
int deleted = 0;
while ( tmp!=NULL && strcmp( tmp->name, word ) != 0 )
{
tmp = tmp->next;
}
if ( tmp != NULL)
{
deleted = 1;
tmp = tmp->next;
while ( *first != tmp )
{
shop *current = *first;
*first = ( *first )->next;
free( current );
}
if ( *first ) ( *first )->prev = NULL;
}
return deleted;
}
Also function print_list is also wrong. In general parameter first or first->next can be equal to NULL. In this case statements like these
first=first->next;
if(first->name==NULL)
while(first->next!=NULL){
result in undefined behaviour.
And the logic itself of the function is wrong.
First of all you have to adopt the parameter list of your function delete_from_list,
so that it is able to delete the first element. Use shop **first instead of
shop *first. Find the element with name word. Delete the first element of your list as long as first element is not the found element.
void delete_from_list(shop **first, char word[MAX], int* check)
// ^^ pointer to pointer of first element
{
// search for elemnt with name word
shop *found = *first;
while ( found != NULL && strcmp(found->name, word) != 0 )
found = found ->next;
if ( found != NULL )
{
// found is element with name word
printf("FOUND!");
// Delete the first element of your list as long as first elment is not found element
shop *temp = *first;
while ( temp != found )
{
shop *next = temp->next;
free( temp );
temp = next;
}
*first = found; // write back the new first element of your list
(*first)->prev = NULL; // predecessor of first element is NULL
}
else
*check=1;
}
I am trying to delete all the nodes on a linked list but I am getting a segmentation fault.
I had code that was working initially but I was only deleting the first node in the list, I want to delete all the nodes and delete all the pointers redundant pointers.
Also if some of you guys could check the function I am using to create the linked list and give me some feedback on whether you think it is ok or where some improvements could be made, I would appreciate it.
Thanks.
Here is the code:
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define MEMORY_SIZE (15)
typedef struct link {
double coeff;
int pow;
struct link * next;
} poly;
poly *polyArray[MEMORY_SIZE];// array of 15 polynomials to play with
// /** The function prototypes */
void createPoly(poly **);
void deletePoly(poly *);
/**
* The main function
*/
int main(void) {
printf("\n\n\t***************************************************");
/* printf("\n\tDemonstrating Polynomial Creation");
printf("\n\t***************************************************");*/
printf("\n\t1st polynomial\t");
createPoly(&polyArray[0]);
showPoly(polyArray[0]);
srand(time(NULL));
// printf("\n\n\tCreating and storing the 2nd polynomial\n");
// createPoly(&polyArray[1]);
// showPoly(polyArray[1]);
showPoly(polyArray[0]);
printf("\n\t***************************************************");
printf("\n\tProgram has Ended, Deleting all polynomials");
printf("\n\t***************************************************");
int count;
for(count = 0; count < MEMORY_SIZE; count++)
{
deletePoly(polyArray[count]);
}
printf("\n\n");
showPoly(polyArray[0]);
return 0;
}//end main function
//////////////////////////////////////////////////////////////////////////////////////
void createPoly(poly **node) {
poly *tempnode; //To hold the temporary last address
tempnode = (poly*)malloc( sizeof(poly) ); //create the first node
*node = tempnode; //Store the head address to the reference variable
int flag = 1 + rand()%3;; // A flag to control the number of terms
int counter;
for( counter = 0; counter <= flag; counter++ )
{
tempnode->pow = ( flag-counter );
tempnode->coeff = ( (double)(rand()%20) )/( (double)(1 + rand()%20) );
if( (counter < flag) && (counter >= 0) )
{
tempnode->next = (poly*)malloc( sizeof(poly) ); //Grow the list
}
else if ( counter == flag )
{
tempnode->next = NULL;
}
tempnode = tempnode->next;
}
}
void deletePoly(poly *node) {
poly *temp;
if( node->next == NULL )
{
free( node );
node = NULL;
}
else
{
while( node->next != NULL )
{
temp = node->next;
free( node );
node = temp;
}//end while
node = NULL;
}//end 'if/else'
}//end function 'deletePoly'
As I understand it, the main function is creating only the first polynomial (poly[0]), but you are trying to delete them all (the loop in the main function goes up to MEMORY_SIZE).
You should also initialize all your pointers to NULL before beginning the program (this is an important feature in C programs) and change the deletePoly this way:
void deletePoly(poly *node) {
poly *temp;
while( node != NULL ) {
temp = node->next;
free( node );
node = temp;
}//end while
node = NULL;
}//end function 'deletePoly'
Write a function that rearranges a linked list to put the nodes in even positions after the nodes in odd positions in the list, preserving the relative order of both the evens and the odds.
I found this problem in the book Algorithm in c writtern by Sedgewick. I have tried but failed. I trid to put all nodes in even positions on another linked list. It's grateful for you to help me. A good idea is enough. Thanks :).
This is my Code in C.
/*
* File: rearranges.c <Exercise 3.36>
* Note: Write a function that rearranges a linked list to put the nodes in even
* positions after the nodes in odd positions in the list, preserving the
* relative order of both the evens and the odds.
* NOTICE: I think it's necessary to use linked list with a dummy head.
* Time: 2013-10-26 10:58
*/
#include <stdio.h>
#include <stdlib.h>
#define LEN 11
typedef struct node *link;
struct node {
int item;
link next;
};
/* Traverse a linked list with a dummy head. */
void traverse(link t) {
link x = t->next;
while (x != NULL) {
printf("%d ", x->item);
x = x->next;
}
putchar('\n');
}
/* Detach even positon nodes from a linked list. */
link detach(link t) {
link u = malloc(sizeof(*u));
link x = t, y = u;
/* x is odd position node. We should ensure that there's still one even
* position node after x. */
while (x != NULL && x->next != NULL) {
y->next = x->next;
x->next = x->next->next;
x = x->next;
y = y->next;
y->next = NULL;
}
return u;
}
/* Combine two linked list */
link combine(link u, link t) {
link x = u;
link y = t->next;
while (y != NULL) {
link n = y->next;
y->next = x->next;
x->next = y;
x = x->next->next;
y = n;
}
return u;
}
/* The function exchanges the position of the nodes in the list. */
link rearranges(link t) {
link u = detach(t);
link v = combine(u, t);
return v;
}
int main(int argc, char *argv[]) {
int i;
link t = malloc(sizeof(*t));
link x = t;
for (i = 0; i < LEN; i++) {
x->next = malloc(sizeof(*x));
x = x->next;
x->item = i;
x->next = NULL;
}
traverse(t);
traverse(rearranges(t));
return 0;
}
curr=head;
end=lastOfList;//last node if size of list is odd or last-1 node
for(int i=1;i<=listSize()/2;i++)
{
end->next=curr->next;
end=end->next;
end->next=null;
if(curr->next!=null)
if((curr->next)->next!=null)
curr->next=(curr->next)->next;
curr=curr->next;
}
You can implement a recursive solution where each call returns an updated node that will serve as the new next reference for the upper caller. We just have to go down the list until we find the last element, and then move every even node to the end of the list, and update the reference to the last element. Here's my solution (please try to do it yourself before looking at my and other solutions):
struct node {
int val;
struct node *next;
};
struct node *reorder_aux(struct node *l, int count, struct node **last);
struct node *reorder(struct node *l) {
struct node *x;
if (l == NULL)
return NULL;
return reorder_aux(l, 1, &x);
}
struct node *reorder_aux(struct node *l, int count, struct node **last) {
struct node *n;
if (l->next == NULL) {
*last = l;
return l;
}
n = reorder_aux(l->next, count+1, last);
if (count & 1) {
l->next = n;
return l;
}
else {
(*last)->next = l;
l->next = NULL;
*last = l;
return n;
}
}
At each step, if the current node l is an even node (as determined by count), then we append this node to the end, and tell the upper caller that its next pointer shall be updated to our next (because our next will be an odd node). In case we're an odd node, we just have to update our next pointer to whatever the recursive call returned (which will be a pointer to an odd node), and return the current node, since we will not move ourselves to the end of the list.
It's a nice exercise!
#include <stdio.h>
struct list {
struct list *next;
int ch;
};
void swap_odd_even (struct list **pp)
{
struct list *one, *two ;
for( ; (one = *pp) ; pp = &one->next) {
two = one->next;
if (!two) break;
*pp = two;
one->next = two->next;
two->next = one;
}
}
struct list arr[] =
{ {arr+1, 'A'} , {arr+2, 'B'} , {arr+3, 'C'} , {arr+4, 'D'}
, {arr+5, 'E'} , {arr+6, 'F'} , {arr+7, 'G'} , {arr+8, 'H'}
, {arr+9, 'I'} , {arr+10, 'J'} , {arr+11, 'K'} , {arr+12, 'L'}
, {arr+13, 'M'} , {arr+14, 'N'}, {arr+15, 'O'} , {arr+16, 'P'}
, {arr+17, 'Q'} , {arr+18, 'R'} , {arr+19, 'S'} , {arr+20, 'T'}
, {arr+21, 'U'} , {arr+22, 'V'}, {arr+23, 'W'} , {arr+24, 'X'}
, {arr+25, 'Y'} , {NULL, 'Z'} };
int main (void) {
struct list *root , *ptr;
root = arr;
for (ptr=root ; ptr; ptr = ptr->next ) {
printf( "-> %c" , ptr->ch );
}
printf( "\n" );
printf( "Swap\n" );
swap_odd_even ( &root);
for (ptr=root ; ptr; ptr = ptr->next ) {
printf( "-> %c" , ptr->ch );
}
printf( "\n" );
return 0;
}
In the following, every time swap_nodes is called another odd sinks to the last sunk odd. The evens are grouped together on each iteration and they bubble up to the end of the list. Here is an example:
/*
[0]-1-2-3-4-5
1-[0-2]-3-4-5
1-3-[0-2-4]-5
1-3-5-[0-2-4]
*/
#include <stdio.h>
#include <stdlib.h>
#define LIST_LENGTH 10
struct node{
int id;
struct node *next;
};
void print_list(struct node *current)
{
while(NULL != current){
printf("node id = %d\n",current->id);
current = current->next;
}
printf("Done\n");
}
struct node *swap_nodes(struct node *head_even, struct node *tail_even, struct node *next_odd)
{
tail_even->next = next_odd->next;
next_odd->next = head_even;
return next_odd;
}
struct node *reorder_list(struct node *head)
{
struct node *head_even;
struct node *tail_even;
struct node *next_odd;
struct node *last_odd;
if(NULL == head->next){
return head;
}
head_even = head;
tail_even = head;
next_odd = head->next;
last_odd = head->next;
head = swap_nodes(head_even, tail_even, next_odd);
if(NULL != tail_even->next){
tail_even = tail_even->next;
}
while (NULL != tail_even->next) {
next_odd = tail_even->next;
last_odd->next = swap_nodes(head_even, tail_even, next_odd);
last_odd = last_odd->next;
if(NULL != tail_even->next){
tail_even = tail_even->next;
}
}
return head;
}
int main(void)
{
int i;
struct node *head = (struct node *) malloc(LIST_LENGTH*sizeof(struct node));
struct node *mem = head;
if(NULL == head){
return -1;
}
struct node *current = head;
for(i=0;i<LIST_LENGTH-1;i++){
current->next = current + 1;
current->id = i;
current = current->next;
}
current->next = NULL;
current->id = i;
head = reorder_list(head);
print_list(head);
free(mem);
return 0;
}
I'm implementing a linked list and it needs to have a function that when given a head of a linked list and a cstring, it finds and deletes a node whose value is the cstring.
typedef struct node
{
char entry[21];
struct node* next;
} node;
/*returns true if node with phrase value found, otherwise false*/
bool findAndRemove(node* root, char phrase[21])
{
if(root != NULL)
{
node* previous = NULL;
while(root->next != NULL)
{
if(strcmp(root->entry, phrase) == 0)//found
{
if(previous == NULL)//node to delete is at head
{
node* tmp = root;
root = root->next;
free(tmp);
return true;
}
previous->next = root->next;
free(root);
return true;
}
previous = root;
root = root->next;
}
return false;
}
}
It works alright but when deleting the head some garbage gets printed out. What is happening and how can I fix this? Do I have any memory leaks? Out of curiosity is the term "root" or "head" more commonly used for the first node in a linked list?
The first thing to realise is that removing an element from a linked list involves changing exactly one pointer value: the pointer that points at us. This can be the external head pointer that points to the first list element, or one of the ->next pointers inside the list. In both cases that pointer needs to be changed; its new value should become the value of the ->next pointer of the node to be deleted.
In order to change some object (from within a function) we need a pointer to it. We need to change a pointer, so we will need a pointer to pointer.
bool findAndRemove1(node **ptp, char *phrase)
{
node *del;
for( ;*ptp; ptp = &(*ptp)->next) {
if( !strcmp((*ptp)->entry, phrase) ) { break; } //found
}
/* when we get here, ptp either
** 1) points to the pointer that points at the node we want to delete
** 2) or it points to the NULL pointer at the end of the list
** (in the case nothing was found)
*/
if ( !*ptp) return false; // not found
del = *ptp;
*ptp = (*ptp)->next;
free(del);
return true;
}
The number of if conditions can even be reduced to one by doing the dirty work in the loop,and returning from the loop but that would be a bit of a hack:
bool findAndRemove2(node **ptp, char *phrase)
{
for( ;*ptp; ptp = &(*ptp)->next) {
node *del;
if( strcmp((*ptp)->entry, phrase) ) continue; // not the one we want
/* when we get here, ptp MUST
** 1) point to the pointer that points at the node we want to delete
*/
del = *ptp;
*ptp = (*ptp)->next;
free(del);
return true;
}
return false; // not found
}
But what if the list is not unique, and we want to delete all the nodes that satisfy the condition? We just alter the loop logic a bit and add a counter:
unsigned searchAndDestroy(node **ptp, char *phrase)
{
unsigned cnt;
for( cnt=0 ;*ptp; ) {
node *del;
if( strcmp((*ptp)->entry, phrase) ) { // not the one we want
ptp = &(*ptp)->next;
continue;
}
/* when we get here, ptp MUST point to the pointer that points at the node we wish to delete
*/
del = *ptp;
*ptp = (*ptp)->next;
free(del);
cnt++;
}
return cnt; // the number of deleted nodes
}
Update: and a driver program to test it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
typedef struct list {
struct list *next;
char entry[20];
} node;
void node_add( node **ptp, char *str)
{
node *new;
for ( ; *ptp; ptp = &(*ptp)->next) {
if (strcmp ((*ptp)->entry, str) < 0) continue;
}
new = malloc (sizeof *new);
strcpy(new->entry, str);
new->next = *ptp;
*ptp = new;
}
int main (void)
{
node *root = NULL;
unsigned cnt;
node_add (& root, "aaa" );
node_add (& root, "aaa" );
node_add (& root, "bbb" );
node_add (& root, "ccc" );
node_add (& root, "aaa" );
cnt = seachAndDestroy( &root, "bbb" );
printf("Cnt(bbb) := %u\n", cnt );
cnt = seachAndDestroy( &root, "ccc" );
printf("Cnt(ccc) := %u\n", cnt );
cnt = seachAndDestroy( &root, "aaa" );
printf("Cnt(aaa) := %u\n", cnt );
printf("Root now = %p\n", (void*) root );
return 0;
}
And the output:
plasser#pisbak:~/usenet$ ./a.out
Cnt(bbb) := 1
Cnt(ccc) := 1
Cnt(aaa) := 3
Root now = (nil)
You are changing the root inside the function, thus you need to pass a double pointer:
bool findAndRemove(node** root, char phrase[21])
{
node* iterate = *root;
if(root != NULL && *root != NULL)
{
node* previous = NULL;
while(iterate->next != NULL)
{
if(strcmp(iterate->entry, phrase) == 0)//found
{
if(previous == NULL)//node to delete is at head
{
node* tmp = iterate;
*root = iterate->next;
free(tmp);
return true;
}
previous->next = iterate->next;
free(iterate);
return true;
}
previous = iterate;
iterate = iterate->next;
}
return false;
}
}
You construct a list by pointing to the first node.
Then you delete the first node, but do not update the pointer to the list to point to the second one
Just make your function check if you are deleting the first node, and always return a pointer to the first pointer of the final list. Alternatively, instead of node *root parameter, pass node **root so you can modifiy the reference in your function (although I don't like this way of working).