Segmentation fault deleting nodes from singly linked list - c

this is the case i am working on
[11] -> [12] -> [13] -> NULL
I am trying to delete the elements from the liked list above(example) but I keep getting segfault and on running GDB doesnot help much. I am not looking for an answer but and explanation on where I am going wrong logically.
here is the code
int
List:: remove( int val )
{
ListNode *headNode = _head;
ListNode *tempNode = NULL;
if(headNode->_value == val){
tempNode = headNode->_next;
delete headNode;
_head = tempNode;
}
else
{
while(headNode->_value != val){
tempNode = headNode;
headNode = headNode->_next;
}
tempNode->_next = headNode->_next;
delete headNode;
}
}

You're not accounting for the following conditions:
The list may be empty; i.e. _head is NULL;
The value may not be in the list at all.
Your function is declared to return int, but makes no such return
Assuming the rest of your code is correct (and that is a big assumption), I'm all-but-certain this is what you're trying to do:
void List::remove( int val )
{
ListNode *headNode = _head;
ListNode *tempNode = NULL;
while (headNode && headNode->_value != val)
{
tempNode = headNode;
headNode = headNode->next;
}
if (headNode)
{
if (tempNode)
tempNode->next = headNode->next;
else
_head = headNode->next;
delete headNode;
}
}
Alternatively, if so inclined this can get (arguably) simpler utilizing a pointer-to-pointer to traverse the pointers in the list, not just their values. It is worth investigating how the following works, which still covers all the bases described previously, but does so using the actual pointers in the list nodes themselves, including _head, by-address rather than by-value, thereby eliminating the need for a walk-behind temporary pointer:
void List::remove( int val )
{
ListNode **pp = &_head;
while (*pp && (*pp)->_value != val)
pp = &(*pp)->next;
if (*pp)
{
ListNode *p = *pp;
*pp = p->next;
delete p;
}
}

In your remove method you are assuming there are always elements in your list. - What if it is empty?
What if the value isn't in the list? You need to handle this case as well.
You're headed in the right direction - there are just a few cases that you haven't considered that can lead you to seg fault.

Example of forward traversal with deletion (forward-only linked list):
// Start from the beginning (head), then while the current isn't null,
// move to the next node.
for (ListNode* current = head; current != null; current = current->next) {
// Check the next item if there is one, and remove it if it matches the value.
// We check the next one because you can't delete the current node in a
// forward only linked list (can in a doubly-linked list however)
if (current->_next != nullptr && current->_value == value) {
// Make this item point to the next next item
// (Since we're gonna delete the next item)
current->_next = current->_next->next;
// Delete the next item.
delete current->_next;
}
}

Related

Remove last node of a linked list, and add this to another linked list

I'm trying to figure out how to manipulate linked lists. I want to remove the end node of a given linked list and add this to the end of another given linked list.
For some reason I can not get my pointers right, well- at least that is where I think the problem lays.
(This method sits in a while loop, so one list keeps getting smaller while the other one grows.)
void movenode(struct Node **cards,struct Node **column)
{
struct Node *head = NULL;
struct Node *tmp,*head1 = *cards;
struct Node *tmp2,*head2 = *column;
if (*cards == NULL || (*cards)->next == NULL){
return;
}
while (tmp->next != NULL) {
head->next = tmp;
tmp = tmp->next;
}
while (tmp2->next != NULL) {
tmp2 = tmp2->next;
}
head->next = NULL;
tmp2->data = tmp;
tmp2->next = NULL;
*cards = head1;
*column = head2;
}
Hope someone is able to help me better understand this.
For some reason I can not get my pointers right, well.. atleast that is where I think the problem lays.
You're right, but it's a little more than that. For example, after struct Node *head = NULL; nothing modifies the value in head, so every time you do head->next you're accessing memory at "NULL + a small offset" (and will probably crash).
To remove the last entry from a singly linked list, you have to find the entry before the last entry (so that you can modify its next); and to add an entry to a linked list you have to find the last entry (so that you can modify its next). With this in mind we can break it into 5 parts:
Do sanity checks
Find the entry before the last entry in the *cards list
Remove the last entry in the *cards list
Find the last entry in the *column list
Add the (removed) entry to the end of the *columns list
You can implement each of these 5 pieces one at a time (and test them). This is an important part of programming - breaking more complex stuff into simpler easier things.
The resulting code might look something like (untested):
void movenode(struct Node **cards,struct Node **column) {
struct Node *temp = *cards;
struct Node *removed;
// Do sanity checks
if (temp == NULL) {
return;
}
// Find the entry before the last entry in the `*cards` list
if(temp->next != NULL) {
while(temp->next->next != NULL) {
temp = temp->next;
}
}
// Remove the last entry in the `*cards` list
if(temp == NULL) {
// The last entry was the first entry
removed = temp;
*cards = NULL;
} else {
removed = temp->next;
temp->next = NULL;
}
// Find the last entry in the `*column` list
temp = *column;
if(temp != NULL) {
while(temp->next != NULL) {
temp = temp->next;
}
}
// Add the (removed) entry to the end of the `*columns` list
if(temp == NULL) {
// There was no last entry (list was empty)
*column = removed;
} else {
temp->next = removed;
}
}
I'm not entirely sure about the mechanics of your solution so I'll offer a separate implementation and solution.
typedef struct Node {
void *data;
struct Node *next;
}
void poppush(Node *popHead, Node *pushHead) {
Node *pushLastNode = pushHead;
while (pushLastNode->next != NULL) {
pushLastNode = pushLastNode->next;
}
Node *popLastNode = popHead;
while (popLastNode->next != NULL) {
popLastNode = popLastNode->next;
}
Node *popSecondLastNode = popHead;
while (popSecondLastNode->next != popLastNode) {
popSecondLastNode = popSecondLastNode->next;
}
popSecondLastNode->next = NULL;
pushLastNode->next = popLastNode;
}
However, for operations such as these, I would recommend using a doubly-linked list and/or create some functions dedicated to managing the lists.

Issues with linked list and pointers (C)

I am writing a C program to sort a linked list according to the largest values. I met an issue whereby the program just hangs when the program reached "prevPtr->next = headPtr".
I want the prevPtr->next to equate to headPtr, if the sum of prevPtr is larger than the sum of headPtr, however the program just hangs there.
compareNodes() function is used to compare the nodes to see if newNode has the same name as any other structs in the linked list, then it will add in the sum.
sortSimilarNodes() function is used to sort the nodes according to the sum of each struct.
The struct is here below:
struct purchase {
char name[30];
double sum;
struct purchase * next;
} ;
LOG * compareNodes(LOG * headPtr, char * name, char * price){
.
.
.
while (curPtr != NULL) {
if (strcmp(newNode->name, curPtr->name)==0) {
curPtr->sum += newNode->sum;
free(newNode);
similar = 1;
break;
}
//advance to next target
prevPtr = curPtr;
curPtr = curPtr->next;
}
/*if (curPtr == NULL){
if(strcmp(newNode->name, prevPtr->name)==0){
prevPtr->sum += newNode->sum;
free(newNode);
similar = 1;
}
}*/
if (similar == 1){
headPtr = sortSimilarNodes(curPtr, headPtr);
}
else{
headPtr = sortNodes(newNode, headPtr);
}
return headPtr;
}
LOG * sortSimilarNodes(LOG * newPtr, LOG * headPtr){
LOG * curPtr;
LOG * prevPtr;
if(headPtr->sum < newPtr->sum){
newPtr->next = headPtr;
return newPtr;
}
prevPtr = headPtr;
curPtr = headPtr->next;
while (curPtr == NULL){
}
while (curPtr != NULL){
if(strcmp(curPtr->name, newPtr->name)==0){
break;
}
prevPtr = curPtr;
curPtr = curPtr->next;
}
return headPtr;
}
This is the output of the program.
Thank you!
It's hard to tell from your code, because you haven't posted all of it, but you seem to have some misconceptions about linked lists. In particular:
There is no need for new nodes unless you really add new nodes to the list. That also means that you don't call malloc except when adding nodes. (There's no malloc in your code, but a suspicious free in your comparison function. Comparing does not involve creating or destroying anything; it just means to look what is already there.)
A corollary to the first point is that there should be no nodes in an empty list, not even dummy nodes. An empty list is a list whose head is NULL. Make sure that you initialise all head pointers before creating a new list:
LOG *head = NULL; // empty list
When you sort the list, the order of the list has changed and the old head is invalid. You cater for that by returning the new head:
head = sort(head);
But that seems redundant and it also seems to imply that the two pointers can be different. That's not the case, because the old pointer will point somehwre in the sorted list, not necessarily at its head. It's probably better to pass the head pointer's address in order to avoid confusion:
sort(&head);
Sorting linked lists can be tricky. One straightforward way is selection sort: Find the node with the highest value, remove it from the original list and add it at the front of a new list. Repeat until there are no more nodes in the original list.
Adding a new node n at the front of a list given by head is easy:
n->next = head;
head= n;
Adding a new node at the end of a list that is given by head is a bit more involved:
LOG **p = &head;
while (*p) p = &(*p)->next;
*p = n;
n->next = NULL;
Here, p is the address of the pointer that points to the current node, *p. After walking the list, that address is either the address of the head node (when the list is empty) or the address of the next pointer of the precedig node.
You could achieve something similar by keeping a prev pointer, but the pointer-to-pointer solution means that you don't have to treat the cases where there is no previous node specially at the cost of some extra & and * operators.
With that, your sorting routine becomes:
void sortByName(LOG **head)
{
LOG *sorted = NULL;
while (*head) {
LOG **p = head; // auxiliary pointer to walk the list
LOG **max = head; // pointer to current maximum
LOG *n; // maximum node
while (*p) {
if (strcmp((*p)->name, (*max)->name) > 0) max = p;
p = &(*p)->next;
}
n = *max;
*max = (*max)->next;
n->next = sorted;
sorted = n;
}
*head = sorted;
}
If you want to sort by sum, change the comparison to:
if ((*p)->sum > (*max)->sum) max = p;
Call the function like this:
LOG *head = NULL;
insert(&head, "apple", 2.3);
insert(&head, "pear", 1.7);
insert(&head, "strawberry", 2.2);
insert(&head, "orange", 3.2);
insert(&head, "plum", 2.1);
sortByName(&head);
print(head);
destroy(&head);
with the insert, destroy and print functions for completeness:
void insert(LOG **head, const char *name, double sum)
{
LOG *n = malloc(sizeof(*n));
if (n) {
snprintf(n->name, sizeof(n->name), "%s", name);
n->sum = sum;
n->next = *head;
*head = n;
}
}
void destroy(LOG **head)
{
LOG *n = *head;
while (n) {
LOG *p = n;
n = n->next;
free(p);
}
*head = NULL;
}
void print(LOG *l)
{
while (l) {
printf("%s: %g\n", l->name, l->sum);
l = l->next;
}
puts("");
}

Linked List Insertion & Selection

I define a linked list in the same way as it is commonly used, i.e. with a data part and a
self referencing pointer. My logic of insertion is as follows:
struct node
{
int data; //or any type.
struct node *nextPtr;
}*start = NULL;
//main
struct *newPtr = (struct node *)malloc(sizeof(struct node *));
scanf("%d", newPtr->data); //or cout
newPtr->nextPtr = NULL;
if(start == NULL)
start = newPtr;
else
{
while(tempPtr->nextPtr != NULL)
{
tempPtr = tempPtr->nextPtr;
}
tempPtr->nextPtr = newPtr;
}
i) Is this logic correct?
ii) a) I possibly get a run-time error, when I insert two nodes (in one system) or three nodes(in another).
b) The nodes are inserted in the correct order, every time I insert a node.
Is the run-time error as a result of this code...???
struct node
{
int data; //or any type.
struct node *nextPtr;
}*start = NULL;
//main
struct *newPtr = (struct node *)malloc(sizeof(struct node));// You dont need * here
scanf("%d", newPtr->data); //or cout
newPtr->nextPtr = NULL;
if(start == NULL)
start = newPtr;
else
{
tempPtr = start; // you missed this.
while(tempPtr->nextPtr != NULL)
{
tempPtr = tempPtr->nextPtr;
}
tempPtr->nextPtr = newPtr;
}
disregard the answer as it is c++, the original question was tagged c++
The original code, once the small issues are solved (actual allocation of the node, setting the value, definition of the temporary pointer to help walk the list) should work. But there are other approaches that you can take to simplify the code (well, not that it is hugely complex), which basically imply finding the point of insertion before creation first then creating the new element:
Node** insertPoint = &start;
while (*insertionPoint)
insertionPoint = &((*insertionPoint)->next);
*insertionPoint = new Node(value);
Use a pointer to pointer to walk through the list, initialized with the address of the head pointer move it until it refers to the Node* where the new element will be appended (note, appended, not inserted). Then create the new node in that position. This assumes that the Node constructor takes care of copying the value and initializing the next pointer.
Alternatively you can write this recursively and let the compiler perform the tail optimization for you (it might be a bit simpler to read, some people find recursion simpler, some don't):
void append( Node*& tail, Value value ) {
if ( tail==NULL )
list = new Node(value);
else
append( list->next, value );
}
Calling code:
append( start, 100 ); // assuming nits contained in the list
In this case, instead of a double pointer we can use a reference to the pointer, as we don't need to modify it
struct node *newPtr, **hnd;
newPtr = malloc(sizeof *newPtr);
if (!newPtr) barf();
scanf("%d", &newPtr->data);
newPtr->nextPtr = NULL;
for(hnd = &start; *hnd; hnd = &(*hnd)->next) {;}
*hnd = newPtr;

reverse linked list recursively - different function signature

There are many posts with probably with same question but the problem says it has to be done by
node* reverseList (node * lh)
{
if(lh==NULL)............ ;
else if (lh->next==NULL)...........;
else ...........;
}
the three blanks must be filled
the first two are simply
return NULL
and
return lh
repectively
one way could be just to go down and reverse the pointers but in that case how can i keep the tail intact even after backtracking? is it possible at all?
The trick to solving recursive problems is to pretend that you are done already. To solve this homework by yourself, you need to answer three questions:
How do you reverse an empty list? (i.e. a list with lh set to NULL)?
How do you reverse a list with only one item?
If someone could reverse all items on the list except the initial one for you, where do you add the first item from the initial list to the pre-reversed "tail" portion of the list?
You answered the first two already: NULL and lh are the right answers. Now think of the third one:
else {
node *reversedTail = reverseList(lh->next);
...
}
At this point, reversedTail contains pre-reversed tail of your list. All you need to do is set lh->next to NULL, add it to the back of the list that you are holding, and return reversedTail. The final code looks like this:
else {
node *reversedTail = reverseList(lh->next);
node *p = reversedTail;
while (p->next) p = p->next;
p->next = lh;
lh->next = NULL;
return reversedTail;
}
I think this answers it:
node *reverseList(node *lh)
{
if (!lh) return NULL;
else if (!lh->next) return lh;
else {
node *new_head = reverseList(lh->next);
lh->next->next = lh;
lh->next = NULL;
return new_head;
}
}
It returns the head of the reversed list, i.e. the tail of the original list.
head = reverse_list(head);
Below is an API which does the reversal of a Single linked list, this one of the best algo that i have seen:
void iterative_reverse()
{
mynode *p, *q, *r;
if(head == (mynode *)0)
{ return;
}
p = head;
q = p->next;
p->next = (mynode *)0;
while (q != (mynode *)0)
{
r = q->next;
q->next = p;
p = q;
q = r;
}
head = p;
}

Sorting Linked List in C

I want to add elements to the my linked list order by ascending but my code just hold minimum node of the lists correctly. My function take an argument as data. Anybody have any idea about my fault?
while(Node->nextPtr!=NULL && capture!=1) {
if(Node->nextPtr->data > data){
capture = 1;
Node->nextPtr = Temp;
Temp->nextPtr = nextNode;
}
else {
Node = Node->nextPtr;
nextNode = Node->nextPtr;
}
}
why not something in the lines of:
while(Node->data < data && Node->nextPtr!=NULL) Node = node->nextPtr;
Temp->nextPtr = Node->nextPtr;
Node->nextPtr = Temp;
Seems clearer, and you don't need to keep track of captured and nextPtr.
(I apologize for any small mistake, it's kinda late here :P)
Cheers
//Bubble Sort to sort the elements
void sort(){
struct Stack *prev,*curr;
int temp;
curr=prev=top;
curr=curr->next;
while(curr!=NULL){
prev=top;
while(prev!=curr->next){
if(prev->info<curr->info){
temp = curr->info;
curr->info=prev->info;
prev->info = temp;
}
prev=prev->next;
}
curr=curr->next;
}
}
Ok, your sample code is weird and it has been a while since I did a linked list in C but here you go:
listNode * insertNode(* listNode newNode){
// throw away variable 32 or 64 bits on the stack, either way no worries since
// it will poof after the call.
currNode * listNode ;
// assume list head is a global since it normally would be
currNode = ListHead ;
// start from the list head and move through until you hit the end
// if you have not inserted before the end, tack it onto the end
// this will traverse until you hit the tail or data is greater
while(currNode->next and (newNode->data > currNode->data) ) ;
// insert the new node after current node and there is a next node
if (currNode->next) {
newNode->next = currNode->next ;
newNode->*next->prev = newNode ;
currNode->next = newNode ;
newNode->prev = currNode ;
}
else
{
// we hit the end of the list on traversal so just tack it onto the end.
currNode->next = newNode ;
newNode->prev = currNode ;
newNode-> next = null ;
}
// and finally return the node in its proper position.
return newNode ;
}
Now this function has no idea what type "data" is and that is fine, but typically it is typed someplace or the data is a pointer type and you can push a pointer size_t bits in to get the actual value. Meh I think I got it right.

Resources