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.
Related
I am trying to code for insertion and deletion in linked list.
Here is my code for basic insertion and deletion of nodes in a singly linked list.
There are no errors in the code, but the output on the terminal shows segmentation fault. Can someone explain why am I getting a segmentation fault? And what changes do i make to remove the fault.
I believe the segmentation fault is in the deletion part. Please help.
// class is a type of user defined datatype
class Node {
public:
int data;
Node* next;
//constructor
Node(int data) {
this -> data = data;
this -> next = NULL;
}
// destructor
~Node() {
int value = this -> data;
//memory free krr rhe hain
if(this -> next != NULL){
delete next;
this -> next = NULL;
}
cout << "memory is free for node with data" << value << endl;
}
};
void insertAtHead(Node* &head, int data) {
// creating new node called temp of type Node
Node* temp = new Node(data);
temp -> next = head;
head = temp;
}
void insertAtTail(Node* &head, Node* &tail, int data) {
// //New node create
// Node* temp = new Node(data);
// tail -> next = temp;
// tail = temp;
Node* temp = new Node(data);
if (head == nullptr) { // If this is the first node of the list
head = temp;
} else { // Only when there is already a tail node
tail -> next = temp;
}
tail = temp;
}
void insertAtPosition(Node* &tail, Node* &head, int position, int data) {
// Insert at starting
if(position == 1) {
insertAtHead(head, data);
return;
}
// Code for inserting in middle
Node* temp = head;
int cnt = 1;
while(cnt < position-1) {
temp = temp -> next;
cnt++;
}
// Creating a node for data
Node* nodeToInsert = new Node(data);
nodeToInsert -> next = temp -> next;
temp -> next = nodeToInsert;
// Inserting at last position (tail)
if(temp -> next == NULL) {
insertAtTail(head,tail, data);
return;
}
}
void deleteNode(int position, Node* &head) {
//deleting first or starting node
if(position == 1) {
Node* temp = head;
head = head -> next;
//memory free start node
temp -> next = NULL;
delete temp;
} else {
// deleting any middle node
Node* curr = head;
Node* prev = NULL;
int cnt = 1;
while(cnt <= position) {
prev = curr;
curr = curr -> next;
cnt++;
}
prev -> next = curr -> next;
curr -> next = NULL;
delete curr;
}
}
void print(Node* &head) {
Node* temp = head;
while(temp != NULL) {
cout << temp -> data << " ";
temp = temp -> next;
}
cout << endl;
}
int main() {
Node* head = nullptr; // A list has a head
Node* tail = head; // a tail.
insertAtHead(head, 10); // pass the head
insertAtTail(head, tail, 20);
insertAtTail(head, tail, 30);
insertAtHead(head, 5);
print(head); // Print the whole list
cout << "head" << head -> data << endl;
cout << "tail" << tail -> data << endl;
deleteNode(1, head);
print(head);
}
The problem is not with the delete function since even commenting it out leads to segmentation fault.
The problem is that you are initializing tail = head which is set to nullptr at the start. However, when you insertAtHead, you set the value of head but leave the tail to nullptr. You need to do tail = head when adding the first node (when head == nullptr).
Refer below for working code:
// Online C++ compiler to run C++ program online
#include <iostream>
using namespace std;
// class is a type of user defined datatype
class Node {
public:
int data;
Node* next;
//constructor
Node(int data) {
this -> data = data;
this -> next = NULL;
}
// destructor
~Node() {
int value = this -> data;
//memory free krr rhe hain
if(this -> next != NULL){
delete next;
this -> next = NULL;
}
cout << "memory is free for node with data" << value << endl;
}
};
void insertAtHead(Node* &head,Node* &tail, int data) {
// creating new node called temp of type Node
Node* temp = new Node(data);
temp -> next = head;
if (head == nullptr)
tail = temp; //inializing tail
head = temp;
}
void insertAtTail(Node* &head, Node* &tail, int data) {
// //New node create
// Node* temp = new Node(data);
// tail -> next = temp;
// tail = temp;
Node* temp = new Node(data);
if (head == nullptr) { // If this is the first node of the list
head = temp;
} else { // Only when there is already a tail node
tail -> next = temp;
}
tail = temp;
}
void insertAtPosition(Node* &tail, Node* &head, int position, int data) {
// Insert at starting
if(position == 1) {
insertAtHead(head,tail, data);
return;
}
// Code for inserting in middle
Node* temp = head;
int cnt = 1;
while(cnt < position-1) {
temp = temp -> next;
cnt++;
}
// Creating a node for data
Node* nodeToInsert = new Node(data);
nodeToInsert -> next = temp -> next;
temp -> next = nodeToInsert;
// Inserting at last position (tail)
if(temp -> next == NULL) {
insertAtTail(head,tail, data);
return;
}
}
void deleteNode(int position, Node* &head) {
//deleting first or starting node
if(position == 1) {
Node* temp = head;
head = head -> next;
//memory free start node
temp -> next = NULL;
delete temp;
} else {
// deleting any middle node
Node* curr = head;
Node* prev = NULL;
int cnt = 1;
while(cnt <= position) {
prev = curr;
curr = curr -> next;
cnt++;
}
prev -> next = curr -> next;
curr -> next = NULL;
delete curr;
}
}
void print(Node* &head) {
Node* temp = head;
while(temp != NULL) {
cout << temp -> data << " ";
temp = temp -> next;
}
cout << endl;
}
int main() {
Node* head = nullptr; // A list has a head
Node* tail = head; // a tail.
insertAtHead(head,tail, 10); // pass the head
insertAtTail(head, tail, 20);
insertAtTail(head, tail, 30);
insertAtHead(head,tail, 5);
print(head); // Print the whole list
cout << "head" << head -> data << endl;
cout << "tail" << tail -> data << endl;
deleteNode(1, head);
print(head);
}
The segfault is actually in the function insertAtTail(), and is because, while you handle the case where head is a null pointer, you do not handle the case where there is a head node but no tail node. The following code fixes this issue:
void insertAtTail(Node* &head, Node* &tail, int data) {
// //New node create
Node* temp = new Node(data);
if (head == nullptr) { // If this is the first node of the list
head = temp;
} else if (tail == nullptr) { // if there's a head but no tail
head -> next = temp;
} else { // Only when there is already a tail node
tail -> next = temp;
}
tail = temp;
}
If you have a look at this part of your code:
int main()
{
Node* head = nullptr; // A list has a head
Node* tail = head; // a tail.
insertAtHead(head, 10); // pass the head
insertAtTail(head, tail, 20);
return 0;
}
tail is a nullptr as you pass it into insertAtTail(head, tail, 20);
Then in insertAtTail you are going to access this nullptr:
void insertAtTail(Node* &head, Node* &tail, int data) {
// //New node create
// Node* temp = new Node(data);
// tail -> next = temp;
// tail = temp;
Node* temp = new Node(data);
if (head == nullptr) {
head = temp;
} else {
// here you have nullptr access resulting in your segmentation fault
tail -> next = temp;
}
tail = temp;
}
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.
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;
}
The following naive code implements a linked list, without printing all the elements in the main function, everything would be fine. However, the LinkedList::printll function will trigger a set fault(Gcc 5.3.0), the problem is related to the appropriate handling of the head node I suppose...
So, is there any way to make this code work with least modification of the printll function?
#include <iostream>
using namespace std;
struct Node{
int value;
Node* next;
};
struct LinkedList{
Node* head= NULL ;
void append(int);
void printll();
};
void LinkedList::append(int data){
Node* cur = head;
Node* tmp = new Node;
tmp->value = data;
tmp->next = NULL;
if(!cur){
cur = tmp; // cur-> head
}
else{
while(cur->next != NULL){
cur = cur->next;
}
cur->next = tmp;
}
std::cout<<cur->value<<std::endl; // cur-> temp
delete tmp; // comment out
}
void LinkedList::printll(){
Node* cur = head;
while(cur->next != NULL){ //
std::cout<<cur->value<<std::endl;
cur = cur->next;
}
}
int main(){
LinkedList LL;
LL.append(5);
LL.append(6);
LL.append(7);
LL.printll(); // --without this, the program is fine
return 0;
}
You have some bugs in append:
if(!cur){
cur = tmp;
}
This only assigns to the local copy. I assume you are trying to set head here, so do that: head = tmp;. Note that in this case, you can't print cur, since you haven't set it. You could print tmp->value though.
Then:
delete tmp;
You only just created it and assigned it into place - why are you deleting it? You know that there is still a pointer to it. Only delete it when you come to clean up the list when you are done with it (which you don't do at all at the moment).
Other than that, your printll won't print the last element - think about when it will stop:
A -> B -> C -> NULL
It will stop on node C, but never print C's value. You can just replace:
while(cur->next != NULL){
with
while(cur != nullptr){
(Also, I don't like endl).
See here for these changes running:
#include <iostream>
struct Node{
int value;
Node* next;
};
struct LinkedList{
Node* head = nullptr ;
void append(int);
void printll();
};
void LinkedList::append(int data){
Node* cur = head;
Node* tmp = new Node;
tmp->value = data;
tmp->next = nullptr;
if(!cur){
head = tmp;
}
else{
while(cur->next != nullptr){
cur = cur->next;
}
cur->next = tmp;
}
}
void LinkedList::printll(){
Node* cur = head;
while(cur != nullptr){
std::cout << cur->value << '\n';
cur = cur->next;
}
}
int main(){
LinkedList LL;
LL.append(5);
LL.append(6);
LL.append(7);
LL.printll();
}
1.you cann't
delete tmp;
cause tmp is a pointer, when you run delete tmp, you delete the object.
2.the print function should like this:
void LinkedList::printll(){
Node* cur = head;
while(cur->next != NULL){ // -> problems is here
std::cout<<cur->value<<std::endl;
cur = cur->next;
}
std::cout<<cur->value<<std::endl;
}
I know this is probably trivial to the c++ programmer, but I'm a noobie trying to figure this out. In my main, if I print my short list manually(cout << head->value etc) it works, but when I use my print function I get a segmentation fault. I've been trying to use a debugger, but I'm not very good at unix/c++ and I'm getting frustrated trying to figure this out.
#include <iostream>
using namespace std;
class ListNode
{
public:
int value;
ListNode* next;
};
void insertAtHead(ListNode** head, int value)
{
ListNode *newNode = new ListNode;
newNode->value = value;
if(head == NULL)
{
*head = newNode;
newNode->next = NULL;
}
else
{
newNode->next = *head;
*head = newNode;
}
}
void printList(ListNode* head)
{
while(head != NULL)
{
cout << head->value << "->";
head = head->next;
}
}
//inserts after the node with given value
void insertAfterNode(ListNode** head,ListNode** newNode, int value)
{
ListNode* current = *head;
while(current != NULL && (current->value != value))
{
//cout << "Im Here";
current = current->next;
cout << current->value;
}
(*newNode)->next = current->next;
current->next = *newNode;
}
int main()
{
ListNode *head;
insertAtHead(&head, 5);
insertAtHead(&head, 10);
ListNode* newNode = new ListNode;
newNode->value = 8;
newNode->next = NULL;
insertAfterNode(&head,&newNode, 5);
printList(head);
}
Check this modifications in your functions
void insertAtHead(ListNode** head, int value)
{
ListNode *newNode = new ListNode;
newNode->value = value;
newNode->next = *head;
*head = newNode;
}
void printList(const ListNode* head)
{
while(head != NULL)
{
cout << head->value << "->";
head = head->next;
}
}
In insertAtHead you are pasing a double pointer, so comparison should be like this.
Added checking for whether *head is null before accessing. and if null adding new node as head
void insertAfterNode(ListNode** head,ListNode** newNode, int value)
{
ListNode* current = *head;
if (current != NULL)
{
while(current != NULL && (current->value != value))
{
//cout << "Im Here";
current = current->next;
cout << current->value;
}
(*newNode)->next = current->next;
current->next = *newNode;
}
else
{
*head = *newNode;
}
}
And in main intialise head before use
int main()
{
ListNode *head = NULL;
insertAtHead(&head, 5);
printList(head); // <== note: by-value, not by address or reference.
You need to check if the next value you are trying to access is not null like this :
void printList(ListNode* head)
{
if (head != NULL)
{
while(head->next != NULL)
{
cout << head->value << "->";
head = head->next;
}
}
}
Dude the first answer is correct
But i would like to make another correction
In your while loop in function insert after node
current!=NULL is incorrect because then your condition will be true if and only if the last node in the list matches the value of 5
Condition should be just while(current->value!=value)
by this you will reach the node having value 5