Hi i'm a new programmer for C, i get a segmentation fault in my linked list program, i was wondering if anyone could help me out. I've posted my code below... If you need furthure information I will post it. Thanks.
#include "list.h"
//+-------------------------------------------------------------
//+ CREATE NODE
//+
//+ Allocate memory for a node of type struct node and
//+ initialize it with d. Return a pointer to the new node.
//+-------------------------------------------------------------
struct node* createNode(int d){
struct node* newNode = malloc(sizeof(struct node)); //create and allocate space in memory for a new node called newNode
newNode->item = d; //newNode's data is the value stored in 'd'
newNode->next = NULL; //sets the pointer to the next node to NULL
return newNode; //return the new node created
}
//+-------------------------------------------------------------
//+ INSERT HEAD NODE
//+
//+ Insert Node n in front of the head of the list, and set
//+ n to be the new head of the list.
//+-------------------------------------------------------------
void insertHead(struct node **headRef, struct node *n){
struct node* newNode = malloc(sizeof(struct node)); //create and allocate space in memory for a new node called newNode
newNode->item = n->item; //newNode's data is assigned the value of the parameter node n''
newNode->next = *headRef; //since we are inserting the node at the head we set the next node to be the head reference
*headRef = newNode; //and then we assign the head reference to the new node created, thus, inserting the head node
}
//+-------------------------------------------------------------
//+ INSERT TAIL NODE
//+
//+ Insert Node n at the tail of the LinkedList.
//+-------------------------------------------------------------
void insertTail(struct node **headRef, struct node *n){
struct node* newNode = malloc(sizeof(struct node)); //create and allocate space in memory for a new node called newNode
newNode = *headRef; //the new node is now the head reference
while(newNode->next != NULL) //while the next node is not equal NULL
newNode = newNode->next; //set the newNode to the next node (this finds the last node)
struct node* tmp = malloc(sizeof(struct node)); //create and allocate space in memory for a new node called tmp
tmp->item = n->item; //the data of tmp is assigned the data of the parameter node 'n'
tmp->next = NULL; //the node following tmp is set to NULL
newNode->next = tmp; //tmp is now set to the next node, thus, becoming the last node i.e. the tail
}
//+-------------------------------------------------------------
//+ COUNT NODES IN LINKED LIST
//+
//+ Count the # of nodes that are part of the LinkedList.
//+-------------------------------------------------------------
int countNodes(struct node *headRef){
int counter = 0; //create a counter variable to store the number of nodes
struct node* current = headRef; //create a new node and assign it the reference to the head node
if(headRef = NULL) return 0; //if the head is NULL, return 0 (no nodes if no head)
while(current != NULL){ //while the current node is not NULL
counter++; //increment the counter
current = current->next; //and move on to the next node, thus, adding 1 to the counter with each node passed
}
return counter; //return the total number of nodes, stored in counter
}
//+-------------------------------------------------------------
//+ FIND NODE
//+
//+ Return the first node that has item = val, return NULL
//+ otherwise.
//+-------------------------------------------------------------
struct node* findNode(struct node *head, int val){
struct node* tmp = malloc(sizeof(struct node)); //create and allocate space in memory for a new node called tmp
*tmp = *head; //node tmp is now referring to the head node of the list
while(tmp != NULL) //while the tmp node is not equal to NULL
{
if(tmp->item == val){ //if the data of the tmp node is equal to the value sent as parameter
return tmp; //return the tmp node
}else{
return NULL; //otherwise, return NULL
}
tmp = tmp->next; //set the tmp node to the next node in the list (traversing)
}
}
//+-------------------------------------------------------------
//+ DELETE NODE
//+
//+ Delete node n from the list and free memory allocated to n.
//+-------------------------------------------------------------
void deleteNode(struct node **headRef, struct node *n){
struct node* toBeDeletedNode = malloc(sizeof(struct node)); //create and allocate space in memory for a new node called toBeDeletedNode
toBeDeletedNode = findNode(*headRef, n->item); //toBeDeletedNode is set to equal the node findNode() returns
//this node should be the node with its data = to the data of the parameter node n
free(toBeDeletedNode); //delete node toBeDeletedNode references and free the space allocated it
}
Here is the test file....
#include "list.h"
#include <assert.h>
#include <sys/types.h>
#include <stdio.h>
// create and insertHead
void test1()
{
struct node *headRef=NULL;
struct node *nptr = NULL;
int h=0;
while(h<5)
insertHead(&headRef,createNode(h++));
h = 0;
for (nptr = headRef; nptr != NULL; nptr = nptr->next, h++)
assert(nptr->item == (4 - h) );
assert(h==5);
printf("HAHA");
}
// create and insertTail
void test2()
{
struct node *headRef=NULL;
struct node *nptr = NULL;
int h=0, t=0;
while(h<5)
insertTail(&headRef,createNode(h++));
h = 0;
for (nptr = headRef; nptr != NULL; nptr = nptr->next, h++)
assert(nptr->item == h);
assert(h==5);
printf("HAHA");
}
// countNodes
void test3()
{
struct node *headRef=NULL;
struct node *nptr = NULL;
int h=0, t=0;
while(h<50)
insertTail(&headRef,createNode(h++));
h = 0;
for (nptr = headRef; nptr != NULL; nptr = nptr->next, h++)
assert(nptr->item == h);
assert(countNodes(headRef) == 50);
}
// findNode
void test4()
{
struct node *headRef=NULL;
struct node *nptr = NULL;
int h=0;
nptr = findNode(headRef, 1);
assert(nptr == NULL);
while(h<50)
insertTail(&headRef,createNode(h++));
nptr = findNode(headRef, 10);
assert(nptr != NULL);
assert (nptr->item = 10);
nptr = findNode(headRef, -10);
assert(nptr == NULL);
}
// deleteNode
void test5()
{
struct node *headRef=NULL;
struct node *nptr = NULL;
int h=0;
while(h<5)
insertTail(&headRef,createNode(h++));
h = 0;
while(h<5) {
nptr = findNode(headRef, h);
assert(nptr != NULL);
deleteNode(&headRef, nptr);
assert(findNode(headRef, h) == NULL);
assert(countNodes(headRef) == (4 - h));
h++;
}
}
/*// sort
void test6()
{
struct node *headRef=NULL;
struct node *nptr = NULL;
int h=0;
int d[5] = {1, 0, -1, 5, 100};
int ds[5] = {-1, 0, 1, 5, 100};
while(h<5)
insertTail(&headRef,createNode(d[h++]));
sort(&headRef);
h = 0;
for (nptr = headRef; nptr != NULL; nptr = nptr->next, h++)
assert(nptr->item == ds[h]);
}*/
int main( int argc, char ** argv )
{
int testNum = 0;
if ( argc < 2 ) {
fprintf(stderr, "\n usage: %s test-num\n", argv[0]);
return 1;
}
testNum = atoi(argv[1]);
switch(testNum){
case 1:
test1();
break;
case 2:
test2();
break;
case 3:
test3();
break;
case 4:
test4();
break;
case 5:
test5();
break;
case 6:
//test6();
break;
default:
fprintf(stderr, "\n usage: %s 1 .. 8\n", argv[0]);
return 1;
}
return 0;
}
I don't know if this is the error, but this line is almost certainly wrong:
if(headRef = NULL) return 0; //if the head is NULL, return 0 (no nodes if no head)
and should be
if(headRef == NULL) return 0; //if the head is NULL, return 0 (no nodes if no head)
It's in countNodes().
There are quite a few issues here.
You are allocating new nodes when you should almost certainly not be, in insertHead, insertTail, findNode, and deleteNode. None of these functions should allocate anything (unless you genuinely want to copy the caller's nodes, which I doubt, in which case you should allocate in insertHead and insertTail, but not the other two, and you should use your own createNode function to do that). Ordinarily I would expect the insertHead function, for example, to simply take the passed-in node and insert it at the head of the list; it would not typically allocate a new node and copy the passed-in node's contents.
The insertTail function needs some work. It leaks a node each time and, I think, it crashes if you append to an empty list (the case in which the new tail is also the new head). Try something like:
void insertTail(struct node **head, struct node *n)
{
struct node **tmp = head;
while (*tmp != NULL)
{
tmp = &((*tmp)->next);
}
*tmp = n;
n->next = NULL;
}
In countNodes you have if (headRef = NULL) but that should be ==, not =.
There's no testing for alloc failures (though this is unlikely to be the cause of your segfault).
Personally, I would use calloc rather than malloc so that your new nodes have zeroed contents.
Your deleteNode function will seqfault if its call to findNode returns NULL.
I'd recommend adding in some asserts, for example:
void insertHead(struct node **head, struct node *n)
{
assert(head != NULL);
assert(n != NULL);
assert(n->next == NULL);
n->next = *head;
*head = n;
}
I'd recommend adding in some debugging aids, for example:
void printNodes(struct node *head)
{
int count = 0;
while (head != NULL)
{
printf("Item[%d] at %p = %d\n", ++count, head, head->item);
head = head->next;
}
}
struct node* tmp = malloc(sizeof(struct node));
where ever you have used this you are creating a blunder, malloc according to the ANSI spec returns the pointer to the allocated address, and you have to manually typecast it to the type that you wish it to be, the correct syntax is
struct node* tmp = (struct node*)malloc(sizeof(struct node));
you are also doing this
*tmp = *head;
you have to assign the pointers NOT the actual values contained at the corresponding memory locations, so write tmp=head because according to the standards, *p denotes the value of the location pointed by the pointer
also bad programming style, you are allocating memory in each and every function, you can create one pointer and allocate memory only once in the main function and then use it in your functions
a nice tips tutorial on segmentation error is here
Related
The code works without error but I cant seem to know why the new node is not being inserted to the beginning of the list. It probably has something to do with the else statement in the first function (insertNode) but I'm not sure, what's going on?
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *link;
};
void insertNode(struct node *head, int x) {
//Create node to be added and add the input integer to it
struct node *temp;
temp = (struct node *)malloc(sizeof(struct node));
temp->data = x;
//Check if there are any existing nodes in the list, if not, the let the head be equal to the new temp pointer
if (head == NULL) {
head = temp;
} else {
//If not, then we need to add the node to the beginning
temp->link = head;
head = temp;
printf("Node was added successfully!\n");
}
}
int findsize(struct node *head) {
//Finds the size of the list
struct node *temp = head;
int count = 0;
while (temp != NULL) {
count++;
temp = temp->link;
}
return count;
}
void printData(struct node *head) {
//Prints the elements of the list
struct node *temp = head;
while (temp != NULL) {
printf("Element: %d\n", temp->data);
temp = temp->link;
}
}
void main() {
//Created a node and allocated memory
struct node *head;
head = (struct node *)malloc(sizeof(struct node));
//Added data to the node and created another one linked to it
head->data = 15;
head->link = (struct node *)malloc(sizeof(struct node));
head->link->data = 30;
head->link->link = NULL;
//Used the above function to add a new node at the beginning of the list
insertNode(head, 5);
//Print the size of the list
printf("The size of the list you gave is: %d\n", findsize(head));
//Print the elements of the list
printData(head);
}
When you insert a node at the beginning of the list, you effectively change the beginning of the list, so this new initial node must be returned to the caller. The prototype for insertNode() must be changed to return the list head or to take a pointer to the list head.
Here is a modified version with the first approach:
#include <stdio.h>
#include <stdlib.h>
struct node {
int data;
struct node *link;
};
struct node *insertNode(struct node *head, int x) {
//Create node to be added and add the input integer to it
struct node *temp;
temp = (struct node *)malloc(sizeof(struct node));
if (temp != NULL) {
temp->data = x;
temp->link = head;
}
return temp;
}
int findsize(struct node *head) {
//Find the size of the list
struct node *temp = head;
int count = 0;
while (temp != NULL) {
count++;
temp = temp->link;
}
return count;
}
void printData(struct node *head) {
//Prints the elements of the list
struct node *temp = head;
while (temp != NULL) {
printf("Element: %d\n", temp->data);
temp = temp->link;
}
}
void main() {
//Created a node and allocated memory
struct node *head = NULL;
//Insert 3 nodes with values 30, 15 and 5
head = insertNode(head, 30);
head = insertNode(head, 15);
head = insertNode(head, 5);
//Print the size of the list
printf("The size of the list you gave is: %d\n", findsize(head));
//Print the elements of the list
printData(head);
//Should free the nodes
return 0;
}
Using the delete_SLL function I want to delete the head of this singly linked list(head = 4). Although I get the correct output, the var struct Node* "temp" holding the value of the head isn't NULL. What is it about the variable "temp" that the free function not like? Is the node temp not Malloc-ed when setting it equal to the list head?
Source:Deleting a Node
Code:
#include <stdio.h>
#include <stdlib.h>
struct Node{
int item;
struct Node* next;
};
struct List{
struct Node* head;
struct Node* tail;
};
int SLL_empty(struct List* lst){
return lst->head == NULL ;
}
//newLst work
struct List newLst(){
struct List lst;
lst.head = NULL;
lst.tail = NULL;
return lst;
}
//Inserts a node to the front of the list[WORKS]
void insert_SLL(struct List* lst, int x){
struct Node* nde = (struct Node*)malloc(sizeof(struct Node));
nde->next = lst->head;
nde->item = x;
if (SLL_empty(lst))
lst->tail=nde;
lst->head = nde;
}
//Deletes a given Node
void delete_SLL(struct List* lst, int x){
struct Node* temp = (struct Node*)malloc(sizeof(struct Node));;
temp = lst->head;
struct Node* prev = NULL;`enter code here`
//If the head has the key
if (temp != NULL && temp->item == x){
lst->head = temp->next;
temp->next = NULL;
free(temp);
}
// stops once the key is found
while(temp != NULL && temp->item != x){
prev = temp;
temp= temp->next;
}
//If not in list
if (temp == NULL) return;
//If middle
if (temp != NULL && temp->item == x){
prev->next = temp->next;
temp->next = NULL;
}
//if at the end
if (temp != NULL && temp->item == lst->tail->item){
lst->tail= prev;
prev->next = NULL;
}
free(temp);
}
int SLL_pop(struct List *list){
struct Node* nde = list->head;
int item = nde->item;
list->head = nde->next;
free(nde);
if (SLL_empty(list))
list->tail = NULL;
return item;
}
int main(int argc, const char * argv[]) {
int i;
struct List list = newLst();
for (i = 0; i < 5; ++i)
insert_SLL(&list, i);
// printf("The length of the linkedLst is: %d\n",SLL_length(&list));
delete_SLL(&list, 4);
while ( list.head != NULL )
printf("Node: %d\n", SLL_pop(&list));
return 0;
}
The main purpose of free() is to ask the OS take the allocated memory back to the system. You might not be able to "see" that but if you try to access any element at the "temp" afterward, you should get an error.
While the "temp" in the program is only a variable. C doesn't require to, and can't change the given pointer to NULL due to pass-by-value sense. It's the programmer's work to remember that this pointer is no longer valid.
Or you can set it to NULL manually each time you free a pointer.
I am trying to print the length of a linked list I created in another .c file called linklist.c from the main.c file. It is not working and I believe is has something to do with pointers and/or memory management over all. I call into question the heap mainly here. some guidance would be appreciated.
#include <stdio.h>
#include <stdlib.h>
#include "node.h"
int main()
{
printf("Hello world!\n");
struct node* mylist = BuildOneTwoThree();
int length = Length(mylist);
printf(mylist->data);
printf(length);
return 0;
}
#include "node.h"
#include <stdio.h>
#include <stdlib.h>
// Return the number of nodes in a list (while-loop version)
int Length(struct node** head) {
int count = 0;
struct node* current = head;
while (current != NULL) {
count++;
current = current->next;
}
return(count);
}
/*
Build the list {1, 2, 3} in the heap and store
its head pointer in a local stack variable.
Returns the head pointer to the caller.
*/
struct node* BuildOneTwoThree() {
struct node* head = NULL;
struct node* second = NULL;
struct node* third = NULL;
head = malloc(sizeof(struct node)); // allocate 3 nodes in the heap
second = malloc(sizeof(struct node));
third = malloc(sizeof(struct node));
head->data = 1; // setup first node
head->next = second; // note: pointer assignment rule
second->data = 2; // setup second node
second->next = third;
third->data = 3; // setup third link
third->next = NULL;
// At this point, the linked list referenced by "head"
// matches the list in the drawing.
return head;
}
/*
Takes a list and a data value.
Creates a new link with the given data and pushes
it onto the front of the list.
The list is not passed in by its head pointer.
Instead the list is passed in as a "reference" pointer
to the head pointer -- this allows us
to modify the caller's memory.
*/
void Push(struct node** headRef, int data) {
struct node* newNode = malloc(sizeof(struct node));
newNode->data = data;
newNode->next = *headRef; // The '*' to dereferences back to the real head
*headRef = newNode; // ditto head points to new node
}
// Given a list and an index, return the data
// in the nth node of the list. The nodes are numbered from 0.
// Assert fails if the index is invalid (outside 0..lengh-1).
int GetNth(struct node* head, int index) {
struct node* current = head;
int answer = 0;
int x = index;
if(x <= 0 || x >= sizeof(head)-1 )
{
return -1;
}
for(int i = 0; i <= sizeof(head)-1; i++){
if (i == x){
return current->data;
}
current = current->next;
}
}
As you can see I use the BuildOneTwoThree function to build the linkedlist and am writing appropriate functions...It crashes when I try to access mylist into output.
For the most part the code seems to function from the point of view of the question only, printf had to be properly formatted.
printf("%i", length);
type cast malloc required
Change **head to *head in function argument Length
Use proper printf statement.
This question is limited to printing lenght of link list. please find code below:
#include <stdio.h>
#include <stdlib.h>
struct node
{
int data;
struct node *next;
};
struct node* BuildOneTwoThree();
int Length(struct node* head);
int main()
{
printf("Hello world!\n");
struct node* mylist = BuildOneTwoThree();
int length = Length(mylist);
printf("data =%d\n",mylist->data);
printf("length = %d",length);
return 0;
}
// Return the number of nodes in a list (while-loop version)
int Length(struct node* head) {
int count = 0;
struct node* current = head;
while (current != NULL) {
count++;
current = current->next;
}
return(count);
}
/*
Build the list {1, 2, 3} in the heap and store
its head pointer in a local stack variable.
Returns the head pointer to the caller.
*/
struct node* BuildOneTwoThree() {
struct node* head = NULL;
struct node* second = NULL;
struct node* third = NULL;
head = (struct node *)malloc(sizeof(struct node)); // allocate 3 nodes in the heap
second = (struct node *)malloc(sizeof(struct node));
third = (struct node *)malloc(sizeof(struct node));
head->data = 1; // setup first node
head->next = second; // note: pointer assignment rule
second->data = 2; // setup second node
second->next = third;
third->data = 3; // setup third link
third->next = NULL;
// At this point, the linked list referenced by "head"
// matches the list in the drawing.
return head;
}
Task is to create objects in the main and have them passed to other functions, which will create a list of type queue. That's the algorithm I'm using:
Write a function of type Node * which will return a pointer to the last Node of the list
To insert a Node at the end of the list, it's required to get a pointer to the last Node
Create a new Node
Assign the newly created Node the object that's been passed to the function
Make next from the last Node point the new one
Here's the code:
typedef struct Node{
int val;
char str[30];
struct Node *next;
}Node;
void printList(const Node * head);
void queue(Node *head, Node *object);
Node *getLast(Node *head);
int main(void){
Node *head = NULL;
Node *object = (Node *)malloc(sizeof(Node));
int c = 0;
while(1){
printf("This int will be stored in Node %d.\n", ++c);
scanf("%d", &object->val);
if(!object->val){
puts("You've decided to stop adding Nodes.");
break;
}
fflush(stdin);
printf("This string will be stored in Node %d.\n", c);
fgets(object->str, 30, stdin);
if(!(strcmp(object->str, "\n\0"))){
puts("You've decided to stop adding Nodes.");
break;
}
queue(head, object);
}
printList(head);
return 0;
}
void printList(const Node *head){
if(head == NULL){
puts("No list exists.");
exit(1);
}
while(1){
printf("|||Int: %d|||String: %s|||\n", head->val, head->str);
if(head->next){
head = head->next;
}
else{
break;
}
}
}
Node *getLast(Node *head){
if(head == NULL){
return NULL;
}
while(head->next){
head = head ->next;
}
return head;
}
void queue(Node *head, Node *object){
Node *last = getLast(head);
Node *tmp = (Node *)malloc(sizeof(Node));
*tmp = *object;
tmp -> next = NULL;
last -> next = tmp;
}
Maybe the problem is in having getLast return NULL. But then again, this exact same thing worked when I created a list consisting only of int.
As pointed out in the comment section, last->next = tmp fails for first call to queue() as getLast() returns NULL. A correct solution would be like this:
void queue(Node **head, Node *object){
Node *last = getLast(*head);
Node *tmp = (Node *)malloc(sizeof(Node));
*tmp = *object;
tmp -> next = NULL;
if (last != NULL)
last -> next = tmp;
else
*head = tmp;
}
and call queue(&head, object) from main().
Suppose that I have a linked list, the next function deletes struct node from the linked list
struct list **lpp;
for (lpp = &list; *lpp != NULL; lpp = &(*lpp)->next)
{
if ((*lpp)->item == i)
{
*lpp = (*lpp)->next;
break;
}
}
please need explain about:
lpp = &(*lpp)->next, can I write it as lpp = lpp->next, is this not the same?
*lpp = (*lpp)->next
the bottom line , I do not see how this function deletes a struct node from the list
lpp points either to the first element of the list or to the next pointer of some element.
By *lpp = (*lpp)->next you are writing it directly into the memory. E.g. consider a list
| el0 | -> | el1 | -> | el2 | -> NULL
list list->next
list from you code points to el0 and lpp = &list.
Now, there are two cases:
el0 matches i: --> list becomes |el0|.next which is el1. After running this function, you have
| el1 | -> | el2 | -> NULL
list list->next
elX matches i (with X>0): lpp is &el_{X-1}.next and by *lpp = ..., this .next will point to elX.next. E.g. assuming el1 matches, you get
| el0 | -> | el2 | -> NULL
lpp = &(*lpp)->next is used to get a reference to next. A simple lpp = lpp->next does not suffice, because it are different types. When you work on lpp->next, a *lpp is like *lpp->next which would dereference the content of the next element.
Single list operations
Although unrelated to this question but due to other discussions, some more code...
Assuming a data structue like
struct node {
int data;
struct node *next;
};
In real code, data would not be a member of this node but struct node would be a mix-in within another object and something like container_of is used to access it. But for this question, keep it as above...
We can define some functions like
void slist_add(struct node *node, struct node *root)
{
node->next = root->next;
root->next = node;
}
void slist_remove(struct node **node)
{
if (node)
*node = (*node)->next;
}
struct node **slist_search(struct node *root, int key)
{
struct node **ptr;
for (ptr = &root->next; *ptr; ptr = &(*ptr)->next) {
if ((*ptr)->data == key)
return ptr;
}
return NULL;
}
Then, we use an empty struct node as an anchor:
int main(void)
{
struct node head = { .next = NULL };
/* add a node */
{
struct node *n = malloc(sizeof *n);
n->data = 23;
slist_add(n, &head);
}
/* add a node */
{
struct node *n = malloc(sizeof *n);
n->data = 42;
slist_add(n, &head);
}
/* verify our expectations... */
assert(head.next != NULL);
assert(head.next->data == 42);
assert(head.next->next != NULL);
assert(head.next->next->data == 23);
assert(head.next->next->next == NULL);
/* remove the node */
{
struct node **ptr = slist_search(&head, 42);
assert(ptr != NULL);
assert(*ptr != NULL);
assert((*ptr)->data == 42);
if (ptr) {
struct node *n = *ptr;
slist_remove(ptr);
free(n);
}
}
/* remove the node */
{
struct node **ptr = slist_search(&head, 23);
assert(ptr != NULL);
assert(*ptr != NULL);
assert((*ptr)->data == 23);
if (ptr) {
struct node *n = *ptr;
slist_remove(ptr);
free(n);
}
}
assert(head.next == NULL);
}
Your code is an extremely simplified and incomplete node delete attempt.
You have to take care of the edge cases as well as actually free the memory.
This line:
*lpp = (*lpp)->next;
is responsible for taking out the node from the list.
It only works if *lpp is the list head and there is another element on the list.
The *lpp points to the node which you do not need anymore and it is replaced by the the next node on the list
(*lpp)->next;
lpp = &(*lpp)->next, can I write it as lpp = lpp->next, is this not
the same?
No it is not. And lpp = lpp->next will not compile.
& is a dereference operator. It is obtaining the address of the node pointer.
You can write this line as
lpp = & ( (*lpp)->next );
and you can recognize (*lpp)->next as the next node pointer on the list.
lpp is a pointer to pointer. *lpp->next is expression known to the compiler but not the lpp->next.
I guess that you misunderstood
lpp = & ( (*lpp)->next );
as
lpp = &* (lpp->next);
and thought that &* would cancel itself out.
If you want to delete the node in the middle of the list you have to connect
the node which exists before the node to be deleted to the node located after the node marked for deletion.
Something similar to:
prev = current;
to_free = current->next; // node to be freed
prev->next = to_free->next; // connect nodes before deletion
free(to_free)
can you please show to me how do I delete a linked list node using
double poniters? – Fela93
I have added the test program for node deletion:
#include <stdio.h>
#include <stdlib.h>
// Basic simple single list implementation to illustrate
// a proper deletion of the node which has a specfic data value.
// Node in List
typedef struct node {
int data;
struct node* next; // pointer to next node
}node;
// returns newly created node
node* node_new(int data)
{
node* new_node = malloc(sizeof(node)); // allocate memory for the node
if (new_node == NULL)
return NULL; // protection
new_node->data = data; // remember the data
new_node->next = NULL; // no next node
return new_node; // return new created node
}
// The method creates a node and prepends it at the beginning of the list.
//
// Frequently used names for this method:
//
// insert at head
// add first
// prepend
//
// returns new head or NULL on failer
node* add_node(node **head, node* new_node)
{
// Add item to the front of the in_list, return pointer to the prepended node (head)
if(head == NULL)
return NULL;
if(new_node == NULL) // problem, not enough memory
return NULL; // in_list->head has not changed
/*
new_node
|*| --> NULL
next
*/
if(*head == NULL) // if list is empty
{
*head = new_node; // the new_node becomes a head
}
else // list already have a head node
{
/*
|2|-->|1|-->NULL
^
|
*
head (2) (list pointer)
*/
new_node->next = *head; // now, the new node next pointer points to the node pointed by the list head, see below:
/*
new_node
|3|--> |2|-->|1|-->NULL
^
|
*
head (list pointer)
*/
*head = new_node; // the list head has to move to new_node ( a new prepanded node)
/*
new_node
|3|--> |2|-->|1|-->NULL
^
|
*
head (3) (list pointer)
*/
}
return *head; // we are returning pinter to new_node
}
// Print out list
void print_nodes(node** head)
{
node* node;
if (head == NULL) {
return;
}
if (*head == NULL){
printf("List is empty!\n");
return;
}
printf("List: ");
node = *head;
while(node != NULL)
{
printf(" %d", node->data);
node = node->next;
}
printf("\n");
}
struct node *find(struct node *start, int data) // find p to be removed
{
node* node;
if (start == NULL)
return NULL;
node = start;
while(node != NULL)
{
if (node->data == data)
return node;
node = node->next;
}
return NULL;
}
int delete(struct node **start, int data)
{
struct node *p, *prev, *next, *to_free;
if (start == NULL) // protection
return 0;
p = find(*start, data); // find element to be removed
if (p == NULL)
return 0;
if (*start == NULL)
return 0; // protection
if(*start == p) // head == p
{
if((*start)->next !=NULL)
{
*start = (*start)->next; // move head
printf("Will be removed: %p\n",p);
free(p); // remove old head
return 1;
}
else // the only node
{
free(p); // free the node pointed by *start (header)
printf("Last node removed\n");
*start = NULL; // header points to NULL
return 1;
}
}
// p != start:
next = *start;
while (next != NULL)
{
prev = next;
to_free = next->next; // candidate to be freed
if( to_free == p )
{
prev->next = to_free->next; // connect nodes before deletion
free(to_free); // now free the remembered `next`
to_free = NULL; // so it does not point to the released memory
return 1;
}
next = next->next; // this node was not a match
} //while
return 0;
}
int main() {
node *head = NULL;
printf("head: %p\n", head);
node *n1 = node_new(1);
node *n2 = node_new(2);
node *n3 = node_new(3);
print_nodes(&head);
add_node(&head, n1);
add_node(&head, n2);
add_node(&head, n3);
printf("head points to: %p\n", head);
// list has 3 elements
print_nodes(&head);
delete(&head, 3);
print_nodes(&head);
delete(&head, 1);
print_nodes(&head);
delete(&head, 2);
print_nodes(&head);
printf("head points to: %p\n", head);
print_nodes(&head);
return 0;
}
Output:
head: (nil)
List is empty!
head points to: 0x5617cd3802b0
List: 3 2 1
Will be removed: 0x5617cd3802b0
List: 2 1
List: 2
Last node removed
List is empty!
head points to: (nil)
List is empty!