node not getting deleted if it's the head [closed] - c++

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed last year.
Improve this question
This is my code, the important part at least. Whenever I run it and try to delete the head node, it won't work (the output will be a large negative number). It will work for all other nodes.
Is it something with my code, or you just can't replace the head?
node* displayList(node* head) {
node* curr = head;
while (curr != NULL) {
cout << curr->data << " ";
curr = curr->next;
}
return NULL;
}
node* deleteVal(node* head, int val) {
node* cur, * prev;
if (head == NULL)
return head;
if (head->data == val) {
cur = head->next;
delete head;
head = cur;
return head;
}
cur = head;
prev = NULL;
while (cur->data != val && cur != NULL) {
prev = cur;
cur = cur->next;
}
if (cur == NULL) {
return head;
}
prev->next = cur->next;
return head;
}
int main() {
node* head1 = initNode(), * head2=initNode(), * head3 = initNode();
int val;
head1 = input();
head2 = input();
head3 = input();
conca(head1, head2, head3);
cout << "the concatated list is: ";
displayList(head1);
cout << endl<<"enter the value you want to delete: ";
cin >> val;
deleteVal(head1, val);
cout << "the new list is: ";
displayList(head1);
return 0;
}

For starters the condition of the while loop
while (cur->data != val && cur != NULL) {
prev = cur;
cur = cur->next;
}
must be changed like
while ( cur != nullptr && cur->data != val) {
prev = cur;
cur = cur->next;
}
Also you need indeed to delete the found node like
prev->next = cur->next;
delete cur;
return head;
And in main you have to reassign the pointer to the head node like
head1 = deleteVal(head1, val);
With shown updates the function can look the following way
node* deleteVal(node* head, int val) {
node* cur, * prev;
if (head == NULL)
return head;
if (head->data == val) {
cur = head->next;
delete head;
head = cur;
return head;
}
cur = head;
prev = NULL;
while ( cur != NULL && cur->data != val ) {
prev = cur;
cur = cur->next;
}
if (cur == NULL) {
return head;
}
prev->next = cur->next;
delete cur;
return head;
}
And in main write
head1 = deleteVal(head1, val);

deleteVal() is coded wrong.
When NOT removing the head node, your while loop will exhibit undefined behavior if val is not found in the list. In that situation, cur will become NULL after the last node is checked, and then the loop will try to access cur->data one more time, which is UB.
You need to swap the conditions of the while statement so that cur is checked for NULL before its data member is accessed:
while (cur != NULL && cur->data != val)
Also, if the while loop does find val in the remaining nodes, you are simply unlinking the found node from the list, but you are not actually delete'ing that node, thus you are leaking its memory.
Try this instead:
node* deleteVal(node* head, int val) {
node *cur, *prev;
if (head == NULL)
return head;
if (head->data == val) {
cur = head->next;
delete head;
return cur;
}
// we know the head node doesn't match, no need to
// test it again, so start the loop on the 2nd node...
cur = head->next;
prev = head;
while (cur != NULL && cur->data != val) {
prev = cur;
cur = cur->next;
}
if (cur != NULL) {
prev->next = cur->next;
delete cur;
}
return head;
}
Now, that being said, there are other issues with the code shown.
main() is ignoring the return value of deleteVal(). So, if the node pointed to by head1 were actually removed/deleted from the list, main() has no way of knowing that, and thus ends up passing a now-invalid node* pointer to displayList() afterwards. So, you need to assign the return value of deleteVal() back to head1 to reflect the new list state:
head1 = deleteVal(head1, val);
This is why it is not a good design choice to return a new list pointer by return value (unless you mark it as nodiscard in C++17 and later), as it is too easy to ignore. A better design choice is to pass in the caller's variable by reference/pointer instead, so the function can update the caller's variable directly when needed.
Also, main() is leaking the head1, head2, and head3 nodes when calling input(). You are creating new nodes with initNode(), and then reassigning the pointers to point at new nodes created by input(), thus you lose access to the original nodes from initNode().
In fact, even after calling deleteVal(), you are not freeing any remaining nodes before exiting the program. While it is true that the OS will reclaim all used memory when the program exits, it is best practice to explicitly free anything you allocate.
Also, your deleteVal() is needlessly complex, it can be greatly simplified.
Also, there is no good reason for displayList() to return anything at all.
With that said, try something more like this instead:
void displayList(node* head) {
node* curr = head;
while (curr != NULL) {
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
void deleteVal(node* &head, int val) {
node *cur = head, **prev = &head;
while (cur != NULL) {
if (cur->data == val) {
*prev = cur->next;
delete cur;
return;
}
prev = &(cur->next);
cur = cur->next;
}
}
void deleteList(node* &head) {
node *cur = head, *next;
head = NULL;
while (cur != NULL) {
next = cur->next;
delete cur;
cur = next;
}
}
int input() { // <-- return int, not node* !
...
return ...; // <-- just the user's entered value, not a node wrapping the value
}
int main() {
node* head1 = initNode(), *head2 = initNode(), *head3 = initNode();
head1->data = input();
head2->data = input();
head3->data = input();
conca(head1, head2, head3);
cout << "the concatenated list is: ";
displayList(head1);
cout << "enter the value you want to delete: ";
int val;
cin >> val;
deleteVal(head1, val);
cout << "the new list is: ";
displayList(head1);
deleteList(head1);
return 0;
}

Related

Why is this if statement triggered in this C++ code?

This code is supposed to reverse a linked list. The following code returns an empty linked list even when provided with a non empty list.
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* curr, *prev, *next;
if (head == NULL)
{
return head;
}
curr = head;
prev = NULL;
while (curr != NULL)
{
next = curr -> next;
curr -> next = prev;
prev = curr;
curr = next;
}
head = prev;
return head;
}
};
While this code strangely works where I added a cout statement just to check if the else was triggered.
class Solution {
public:
ListNode* reverseList(ListNode* head) {
ListNode* curr, *prev, *next;
if (head == NULL)
{
cout << "Triggered";
return head;
}
curr = head;
prev = NULL;
while (curr != NULL)
{
next = curr -> next;
curr -> next = prev;
prev = curr;
curr = next;
}
head = prev;
return head;
}
};
Can someone please explain why this is happening?
Pretty simple, you have to initialize the pointers, else it leads to unexpected behavior that includes not showing it at all or just showing it if an initialized cout is triggered - but it doesn't have to do anything and that's up to your compiler implementation.
//cpp17
listNode* curr{}, *prev{}, *next{};
//before
listNode* curr = nullptr, *prev = nullptr, *next = nullptr;
It is still not in the reverse order as you intended to do.
class Solution {
public:
ListNode* reverseList(ListNode* head) {
listNode* curr{}, *prev{}, *next{};
//ListNode* curr, *prev, *next;
if (head == NULL)
{
return head;
}
curr = head;
prev = NULL;
while (next != NULL)
{
next = curr -> next;
curr -> next = prev;
prev = curr;
curr = next;
}
head = prev;
return head;
}
};
cheers :)
Like mentioned before I found time to write a solution for an other approach of solving your problem to reverse a linked list via class. For a better understanding for beginners I skipped the rule of three/five and initialized the list in the main function and not via constructor in the class:
#include <iostream>
class listElement
{
std::string data;
listElement* next;
listElement* last;
public:
void setData(std::string);
void append(std::string);
void displayElements();
void reverseDisplayElements(listElement*);
void freeMemory();
listElement* reverseList(listElement*);
};
void listElement::setData(std::string newData)
{
last = this;
data = newData;
next = nullptr;
}
void listElement::append(std::string newData)
{
// Double linked list
// last->next = new listElement();
// last->next->data = newData;
// last->next->next = nullptr;
// last = last->next;
// Singly linked list
//has next the value nullptr?
//If yes, next pointer
if (next == nullptr)
{
next = new listElement();
next->data = newData;
next->next = nullptr;
}
//else the method again
else
next->append(newData);
}
listElement* listElement::reverseList(listElement* head)
{
//return if no element in list
if(head == nullptr)
return nullptr;
//initialize temp
listElement* temp{};
while(head != nullptr){
listElement* next = head->next;
head->next = temp;
temp = head;
head = next;
}
return temp;
}
void listElement::displayElements()
{
//cout the first entry
std::cout << data << std::endl;
//if the end is not reached, call method next again
if (next != nullptr)
next->displayElements();
}
void listElement::reverseDisplayElements(listElement*head)
{
//recursiv from the last to the list beginning - stop
listElement *temp = head;
if(temp != nullptr)
{
if(temp->next != nullptr)
{
reverseDisplayElements(temp->next);
}
std::cout << temp->data << std::endl;
}
}
void listElement::freeMemory()
{
//If the end is not reached, call the method again
if (next != nullptr)
{
next->freeMemory();
delete(next);
}
}
int main ()
{
//Pointer to the Beginning of the list
listElement* linkedList;
//Creating the first element
linkedList = new listElement();
//Write data in the first element
linkedList->setData("Element 1");
//add more elements
linkedList->append("Element 2");
linkedList->append("Element 3");
linkedList->append("Element 4");
//display list
linkedList->displayElements();
//space divider
std::cout << "\nPrint in reverse order:" << std::endl;
//display list in reverse order
//pass list beginning as stop point
linkedList->reverseDisplayElements(linkedList);
std::cout << std::endl;
linkedList->displayElements();
std::cout << "\nReverse elements:" << std::endl;
linkedList = linkedList->reverseList(linkedList);
linkedList->displayElements();
std::cout << std::endl;
//destruct the list and free memory
linkedList->freeMemory();
delete(linkedList);
return 0;
}
Btw. there are many different solutions for that task.

Unable to create or return Reversed Linked list

Here using the function returnReverseLinkedList I am returning the reversed linked list of the given linked list. But the problem with this approach is that i lose the original linked list. So I make another fucntion called createReversedLinkedList to make a copy of the original linked list and reverse the copy and maintain possession of both.
unfortunately createReversedLinkedList is giving Runtime error.
obviously my end goal is to check if the given linked list is palindrome or not. This issue is just a stepping stone.
Could someone tell me why?
//Check if a linked list is a palindrome
#include <iostream>
using namespace std;
class node
{
public:
int data;
node *next;
node(int data)
{
this->data = data;
this->next = NULL;
}
};
node *returnReverseLinkedList(node *head)
{
// Will Lose original Linked List
if (head == NULL)
return NULL;
else if (head != NULL && head->next == NULL)
return head;
node *prev = NULL;
node *curr = head;
node *tempNext = head->next;
while (tempNext != NULL)
{
curr->next = prev;
prev = curr;
curr = tempNext;
tempNext = tempNext->next;
}
curr->next = prev;
return curr;
}
node *createReversedLinkedList(node *head)
{
if (head == NULL)
return NULL;
else if (head != NULL && head->next == NULL)
return NULL;
else
{
node *temp = head;
node *newHead = NULL;
node *newTail = NULL;
while (temp != NULL)
{
node *newNode = new node(temp->data);
if (newHead == NULL)
{
newHead = newNode;
newTail = newNode;
}
else
{
newTail->next = newNode;
newTail = newNode;
}
}
return returnReverseLinkedList(newHead);
}
}
bool check_palindrome(node *head)
{
node *original = head;
node *reverse = returnReverseLinkedList(head);
while (original->next != NULL || reverse->next != NULL)
{
if (original->data != reverse->data)
return false;
cout << "debug 2" << endl;
original = original->next;
reverse = reverse->next;
}
return true;
}
// #include "solution.h"
node *takeinput()
{
int data;
cin >> data;
node *head = NULL, *tail = NULL;
while (data != -1)
{
node *newnode = new node(data);
if (head == NULL)
{
head = newnode;
tail = newnode;
}
else
{
tail->next = newnode;
tail = newnode;
}
cin >> data;
}
return head;
}
void print(node *head)
{
node *temp = head;
while (temp != NULL)
{
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
int main()
{
node *head = takeinput();
node *revese2 = createReversedLinkedList(head);
print(revese2);
// bool ans = check_palindrome(head);
// if (ans)
// cout << "true";
// else
// cout << "false";
// return 0;
}
As asked by the OP, building a reversed linked is simply done by building as you would a stack (e.g LIFO) rather than duplicating the same original forward chain. For example:
node *createReversedLinkedList(const node *head)
{
node *newHead = NULL;
for (; head; head = head->next)
{
node *p = new node(head->data)
p->next = newHead;
newHead = p;
}
return newHead;
}
Note we're not hanging our copied nodes on the tail of the new list; they're hanging on the head of the new list, and becoming the new head with each addition. That's it. There is no need to craft an identical list, then reverse it; you can reverse it while building the copy to begin with.
A note on the remainder of your code. You have a dreadful memory leak, even if you fix the reversal generation as I've shown above. In your check_palindrome function, you never free the dynamic reversed copy (and in fact, you can't because you discard the original pointer referring to its head after the first traversal:
bool check_palindrome(node *head)
{
node *original = head;
node *reverse = returnReverseLinkedList(head); // only reference to reversed copy
while (original->next != NULL || reverse->next != NULL)
{
if (original->data != reverse->data)
return false; // completely leaked entire reversed copy
original = original->next;
reverse = reverse->next; // lost original list head
}
return true;
}
The most obvious method for combating that dreadful leak is to remember the original list and use a different pointer to iterate, and don't leave the function until the copy is freed.
bool check_palindrome(const node *head)
{
bool result = true;
node *reverse = returnReverseLinkedList(head);
for (node *p = reverse; p; p = p->next, head = head->next)
{
if (p->data != head->data)
{
result = false;
break;
}
}
while (reverse)
{
node *tmp = reverse;
reverse = reverse->next;
delete tmp;
}
return result;
}

Unusual Segmentation Fault

I was trying to delete alternate nodes in a linklist. I observed a strange behaviour.
void delete_alternate_node_LinkedList(Node *head) {
Node *prev = head;
Node *curr = head->next;
while (prev != NULL and curr != NULL) {
prev->next = curr->next;
free(curr);
prev = prev->next;
if (prev != NULL) {
curr = prev->next;
}
}
}
This code works fine except the head being nullptr when I use free to delicate or intentionally keep a memory leak but if I change the line free(curr) with delete curr, I get a segmentation fault.
Can anyone explain me the reason?
Here are the boilerplate codes
class Node {
public:
int data;
Node * next;
Node(int data){
this -> data = data;
this -> next = NULL;
}
~Node() {
if(next) {
delete next;
}
}
};
Node* takeinput() {
int data;
cin >> data;
Node *head = NULL, *tail = NULL;
while(data != -1){
Node *newNode = new Node(data);
if(head == NULL) {
head = newNode;
tail = newNode;
}
else{
tail -> next = newNode;
tail = newNode;
}
cin >> data;
}
return head;
}
void print(Node *head) {
Node *temp = head;
while(temp != NULL) {
cout << temp -> data << " ";
temp = temp -> next;
}
cout << endl;
}
Your destructor has a problem
Let's assume
A->B->C->D->nullptr
Now when you delete B it invokes destructor (if you use free it won't).
it will delete recursively C (which in turn delete D) and ..... till the end
so in next iteration you are holding on to a dangling pointer (C) and getting the segfault when you are trying to derefence it.

linked list insertion, pointer confusion

I've looked around the forums but cant seem to find an answer to this very general question. The class below is a basic singly linked list with pushBack written the standard way.
class linkedList {
private:
typedef struct node {
int data;
struct node *next;
node(int d):data(d), next(NULL){}
}*nodePtr;
nodePtr head, temp, curr;
public:
linkedList():head(NULL), temp(NULL), curr(NULL){}
void pushBack(int d) {
temp = new node(d);
curr = head;
if (curr != NULL) {
while (curr->next != NULL) {
curr = curr->next;
}
curr->next = temp;
} else head = temp;
}
void printAll() {
curr = head;
cout << "list:" << endl;
while (curr) {
cout << curr->data << " ";
curr = curr->next;
}
cout << endl;
}
};
but why cant my pushBack function be written like this?
void pushBack(int d) {
temp = new node(d);
curr = head;
while (curr != NULL) {
curr = curr->next;
}
curr = temp;
}
It should iterate through the list until curr == NULL and then set curr = temp. If the list is empty then it doesnt enter the loop and head will be set to the new node by setting temp to curr (which its self is set to head).
The logic makes perfect sense to me so it must be something else I'm missing.
Thank you for the help!
your function would fail for the first insertion or pushback, i.e, when the head pointer is null to begin with. when you assign head to curr like this:
curr = head;
curr now points to head and not vice versa .When curr is then assigned temp( i.e. when the first node isnserted into this linked list) , you have only reassigned the pointer curr with the location held by temp. Now all you have is a pointer curr pointing to the same location as temp, both of which pointers are not connected to head pointer at all!
a modified version of your code that would work is:
void pushBack(int d)
{
temp = new node(d);
curr = head;
if(curr!=NULL)
{
while (curr != NULL)
{
curr = curr->next;
}
curr = temp;
}
else head=temp;
}

makeList and Print functions for a linked list in C++

The following is my code for making a list by reading in a list of inputs. It is supposed to return a pointer to the list of strings in the order that they are read in. Then in the print function, I want to print out all the elements in the linked list, stopping when the next of the element is NULL. I don't understand why my code isn't working. Any help would be greatly appreciated.
struct Node{
string val;
Node* next;
};
Node* makeList(){
string value;
Node *head = NULL;
Node *current = NULL;
Node *last = NULL;
while (cin >> value){
current = new Node();
if(head== NULL){
head = current;
}
if(last!= NULL){
last->next=current;
}
last=current;
}
if(last != NULL) {
last->next = NULL;
}
return head;
}
void printList (Node* p)
{
Node* tmp = p;
while(tmp->next != NULL) {
tmp = tmp->next;
cout >> tmp->val >> endl;
}
}
You didn't set current->val to value:
current = new Node();
current->val = value; // <--
Change the condition in the while loop of the printList() function from:
while (temp->next != NULL)
to
while (temp != NULL)
and switch the two statements and change >> to <<:
while(tmp != NULL) {
cout << tmp->val << endl;
tmp = tmp->next;
}