Doubly linked list Core dump - c++

Thanks in advance.
I am making a doubly linked list.
Everything was working fine, but I realized that when I added a new class node somewhere in the middle, the left pointer would still be pointing at the node previously before it (now two spaces away).
So I added a new node pointer on line 46.
Then on line 51 I told that node to now point to the new node.
So :
First I had new node temp off in space
Then I make pointer temp2 loop through the list
Lastly I tell temp3 to point to the node after temp2's node
After the function runs, the order should be temp2->temp->temp3
My main point: After I added line 51, my program core dumps(segmentation fault) and closes out.
How can I fix this? It only happens when I add something that isn't taking place of the head pointer.
void add(node *&head, node *&tail, node *&current)
{
node *temp = new node; //creates a pointer pointing to a new class node
cin >> temp->letter; // user input
current = head; // creates a pointer to point at the first node
while (current != NULL) // while list isn't empty
{
if (current->letter == temp->letter)
{ // letter already exists
cout << "DUPLICATE: " << temp->letter << endl << endl;
return;
}
else
{ // loop through list moving tail pointer to the end while checking for duplicates
tail = current;
current = current->right_link;
}
}
current = temp; // current = new added node
if (isEmpty(head))
{ // if first node
temp->left_link = NULL;
temp->right_link = NULL;
head = temp; // head and
tail = temp; // tail both point to first and only node.
}
else
{ // if new letter value is less than head value
if(temp->letter < head->letter)
{
temp->right_link = head; // node points (right) to head
temp->left_link = NULL; // left most node point to nothing.
head->left_link = temp; // head (currently the second node) points (left) to first node
head = temp; // head pointer moves to the first position
}
else
{ // if new node goes anywhere other than head
node *temp2 = head; // new node to cycle through list
while(temp2->right_link != NULL && temp2->right_link->letter < temp->letter)
{ // if temp2 points to a node and that node's value is less than temp node value
temp2 = temp2->right_link;
}
node *temp3 = temp2->right_link;
temp->right_link = temp2->right_link; // when temp2 stops looping, temp will point to
// the same node as temp2.
temp2->right_link = temp; // temp2's current node will point to temp, causing temp
// to be added into the list (after temp2)
temp3->left_link = temp; // point the node (after the newly inserted node) left to new node
temp->left_link = temp2; // connects the left pointer between temp and temp2
if(temp->right_link == NULL)
tail = temp;
}
}
cout << "ADDED : " << temp->letter << endl << endl;
}

if temp2->right_link == NULL
46 node *temp3 = temp2->right_link;
is a NULL pointer, so you can't
51 temp3->left_link = temp;
which should have been obvious if you used a debugger.

Related

how to delete current linked list node without tracking previous node

I was wondering if it's possible to delete a node by value in a linked list in C++ without tracking both 'previous' and 'current' nodes.
What I did is copy next node's information into current node, link current node to next next node, and delete next node.
I've attempted something like below. However, this only works if the node to delete is not the last node. I'm unable to figure out how to accommodate for the last node.
struct Node
{
int data;
Node* next;
};
void LinkedList::deleteNode(int item)
{
Node* tmpNode = m_head;
while (tmpNode != nullptr)
{
if (tmpNode->data == item)
{
if (tmpNode->next != nullptr) // not last node
{
// this works
Node* delNode = tmpNode->next;
tmpNode->data = tmpNode->next->data;
tmpNode->next = tmpNode->next->next;
delete delNode;
}
else // last node
{
// this does not work
delete tmpNode;
tmpNode = nullptr;
}
std::cout << "deleted item " << item << '\n';
return;
}
tmpNode = tmpNode->next;
}
std::cout << "delete failed: item " << item << " not found\n";
}
When you delete a node, you have to set the next of the previous node to nullptr. Otherwise, it will stay pointing to a deleted node.
Suggestion:
At the beginning of the function, create:
Node* previousTmpNode = nullptr;
Store the address of the previous node when you scan the linked list:
Node* previousTmpNode = tmpNode ; //call right before tmpNode = tmpNode->next;
And then call:
previousTmpNode->next = nullptr; //call right after you deleted the last element.
Or, change your nodes so they point backwards (double linked-list).
As this is probably an exercise/home-work, I'll answer in a sudo(untested) manor. And it will just work for the last node.
Node* prev = nullptr;
for(auto track = m_head; track; track = track->next){
if(track->data != item)
continue;
if(!prev){
m_head = track->next;
delete track;
break;
}
prev->next = track->next;
delete track;
break;
}

Insertion in Singly Linked List running on infinite loop

Linked List PrintNode function is running on an infinite loop.
class Node{
public:
int data;
Node* next;
};
Node * head; //first variable of inked list
void Insert(int x){
//insertion at beginning
Node* p = new Node;
p->data = x;
p->next = NULL; //when list is empty
//two scenarios to insert node
//one when linked list is empty
if (head == NULL){
head = p; //head becomes the first node
}
//if linked list is not empty
if (head != NULL){
p->next = head;
head = p; //pointing head at the newly created node
}
}
void PrintNode(Node* head){
for ( Node * temp = head; temp != nullptr; temp = temp->next )
{
cout << temp->data << "->";
}
}
int main (){
head = NULL; //points nowhere
int n;int x;
cin >> n;
for(int i = 0 ; i < n ;i ++){
cout << "Enter element" << endl;
cin >> x;
Insert(x);
}
PrintNode(head);
}
I expect the output to be list printed as for example: 1->2->3-> but,
running on an infinite loop.
The first Node you add ends up pointing at itself. Take a look at this chunk of code from Insert
if (head == NULL){
head = p; //head becomes the first node
}
//if linked list is not empty
if (head != NULL){
p->next = head;
head = p; //pointing head at the newly created node
}
You'll point head at your new Node, then enter the next if since head isn't NULL. If you replace the second if with an else, you should be fine.
Look carefully at this code:
if (head == NULL){
head = p; //head becomes the first node
}
//if linked list is not empty
if (head != NULL){
p->next = head;
head = p; //pointing head at the newly created node
}
When head is NULL both branches of code get run resulting in your head node pointing to itself. The correct code would be:
if (head == nullptr){
head = p; //head becomes the first node
}
//if linked list is not empty
else{
p->next = head;
head = p; //pointing head at the newly created node
}
When you update the head pointer as you insert your first element, both if statements will be executed and the head pointer will never be empty in the second if statement, so it should be if then else, like below
if (head == NULL){
head = p; //head becomes the first node
}
//if linked list is not empty
else if (head != NULL){
p->next = head;
head = p; //pointing head at the newly created node
}

C++ Double Linked List Reverse Print

I am trying to write a reverse print function as part of a doubly linked list. Here are the relevant functions that I have written:
void PLAYER::AddNode(int addID, std::string addName){
nodePtr n = new node; //creates a new node pointer
n->next = NULL; //Make next null
n->prev = NULL; // this will set this to be the ending node
n->ID = addID; //These two lines pass the information into the node
n->name = addName; // ID# and Name Information
if(head != NULL){ // This checks to see if a list is set up.
curr = head; // Make this point to the head.
while(curr->next != NULL){ // Loops through until the NULL is found
curr = curr->next;
}
curr->next = n; //Make the currnet node point to N
n->prev = curr; //Make the previous node connect to curr
n->next = tail; // connect new node to the tail.
}
else{
head = n; //If there is no list, this makes N the first node.
}
Here is the class that prototypes the functions to be used.
class PLAYER
{
public: // Functions go inside PUBLIC
PLAYER();
void AddNode(int addID, std::string addName);
void DeleteNode(int delPlayer);
void SortNode();
void PrintList();
void InsertHead(int AddID, std::string addName);
void PrintReverse();
private: //Variables go into here
typedef struct node{
// ...
std::string name;
int ID;
node* next;
node* prev;
}* nodePtr;
nodePtr head, curr, temp, prev, test, tail;
};
And finally my attempt to create a reverse traversing function to print backwards.
void PLAYER::PrintReverse()
{
curr = head;
while(curr->next != NULL) //Get to the end of the list
{
curr = curr->next;
}
while(curr->prev != NULL) //Work backward and print out the contents
{
std::cout << curr->ID << " " << curr->name << endl;
curr = curr->prev;
}
}
What I would like to do is inside the PrintReverse() function have it initialize via the tail pointer, however I can not figure out the functions to add to PrintReverse() and to AddNode() in order to have the new nodes pointed to by tail.
This is my first question posting here, I hope I covered all my bases. Thank you for any help I can find.
EDIT:
Thank you for all your input. I am relearning data structures and yes this is some self imposed homework on my part to begin to get the logic flowing again.
I will make the changes when I get home tonight.
The following changes would need to be considered.
The PrintReverse function would not need the forward pass to obtain the tail.
void PLAYER::PrintReverse()
{
curr = tail;
while(curr != NULL) //Work backward and print out the contents
{
std::cout << curr->ID << " " << curr->name << endl;
curr = curr->prev;
}
}
There is a problem in how tail is handled in the AddNode function. See the lines where the comments contain [CHANGED] and [ADDED]:
if(head != NULL){ // This checks to see if a list is set up.
curr = head; // Make this point to the head.
while(curr->next != NULL){ // Loops through until the NULL is found
curr = curr->next;
}
curr->next = n; //Make the currnet node point to N
n->prev = curr; //Make the previous node connect to curr
n->next = NULL; // [CHANGED]: we want the last node not to have a successor.
}
else{
head = n; //If there is no list, this makes N the first node.
}
tail = n; // [ADDED]: the last node added is the new tail.
However, a simpler solution is to avoid again the forward pass, and start from tail.
if(tail != NULL){ // This checks to see if a list is set up.
tail->next = n; //Make the old tail node point to N
n->prev = tail;
n->next = NULL;
}
else{
head = n; //If there is no list, this makes N the first node.
}
tail = n; // The last node added is the new tail.

Printing Doubly Linked Lists

I'm currently learning how to work with linked lists, specifically, doubly linked lists, and I have come across a problem with my program when I attempt to print it backwards.
Here is the portion of the code that I need help with:
#include <iostream>
using namespace std;
struct node
{
int data; //int to store data in the list
node *next; //pointer to next value in list
node *prev; //pointer to previous value in list
};
node *appendList(node *current, int newData) //Function to create new nodes in the list
{
node *newNode; //create a new node
newNode = new node;
newNode->data = newData; //Assign data to it
newNode->next = NULL; //At end of list so it points to NULL
newNode->prev = current; //Link new node to the previous value
current->next = newNode; //Link current to the new node
return newNode; //return the new node
}
node *createList(int maxLoop, node *begin, node *current, node *end) //Function to create list
{
//Allocate the starting node
current = new node;
current -> data = 1; //First data value is 1
current -> next = NULL; //next value is NULL
current -> prev = NULL; //previous value is NULL
begin = current; //This is the beginning of the list
for (int count = 2; count <= maxLoop; count++) //Loop to fill the list
{
current = appendList(current, count*count); //Create new nodes and fill with square numbers
}
end = current; //Now we are at the end of the list
return begin; //Return begin, this is the problem; I can't return end as well
}
void printForward (node *p) //Function to print the list forwards
{
node *curr = p; //current is the beginning value of the list
while (curr != NULL) //Continue while current is not at the end of the list
{
cout << curr->data << " "; //Print out the data of current
curr = curr->next; //Move one value along in the list
}
}
void printBackward (node *p) //Function to print the list backwards
{
node *curr = p; //current is the end value of the list
while (curr != NULL) //Continue while current is not at the beginning of the list
{
cout << curr->data << " "; //Print out the data of current
curr = curr->prev; //Move one value back in the list
}
}
int main()
{
//Initialize current, begin, and end
node *current = NULL;
node *begin = NULL;
node *end = NULL;
int maxLoop = 10; //The number of items in the list
cout << "The list has now been created." << endl;
begin = createList(maxLoop, begin, current, end); //function to create the list
cout << "Printed forwards, this list is: ";
printForward(begin); //Function to print the list forwards
cout << endl;
cout << "Printed backwards, this list is: ";
printBackward(end); //Function to print the list backwards
cout << endl;
return 0;
}
The purpose of this program is to create a list, print it forwards, backwards, insert an element, erase an element, and then destroy the list. I have chopped it down to just the create, print forward, and print backward functions.
The issue I have is that in the createList function I am modifying both begin and end but I can only return one or the other. This means that whichever I don't return is still NULL in the main function and therefore does not point to anything. I've tried setting the begin/current/end to not equal NULL but createList won't work if I do that.
Does anyone have any ideas for how I could modify both? Just to be clear, the list HAS TO be created in a function, it would be very easy to just initialize it in the main.
Thanks,
Tristan
Your problem is you're copying the pointers, when you should be passing them by reference, i.e., using a pointer-to-pointer or reference-to-pointer rather than just copying the value the pointer in main is originally pointing to. With what you're doing, you're unable to modify the original pointer variable that was declared in main ... passing-by-reference will allow you to-do that while also keeping all list setup code within your functions.
So for instance, change
node* createList(int maxLoop, node *begin, node *current, node *end)
to
void createList(int maxLoop, node** begin, node** current, node** end)
and then make sure to take the extra dereference into account in the body of your function
Finally, you would call it like:
createList(maxLoop, &begin, &current, &end);
And do the final assign to begin inside the body of the function of createList rather than in main.

Printing Linked List in C++

My following code print just only first element. In print_list() function, it stops after printing first element. It says after first element, head->next is 0. Shouldn't point towards second element?
I want to simply print whole list.
#include<iostream>
#include<cstdlib>
using namespace std;
struct node {
int x;
node *next;
};
node* add_element(node*);
bool is_empty(node*);
void print_list(node*);
node* search(node*);
int main()
{
node *head;
head=NULL;
node* current=head;
for(int i=0;i<5;i=i+1)
{
if (current==NULL)
{
current=add_element(current);
head=current;
}
else{
current=add_element(current);
}
}
cout<<head->next<<endl;
// DOUBT: head->next gives NULL value. It should give me pointer to 2nd node
print_list(head);
}
node* add_element(node* current)
{
node* temp;
temp=new node;
temp->next=NULL;
cout<<"enter element"<<endl;
cin>>temp->x;
current=temp;
return current;
}
bool is_empty(node* temp)
{
return temp==NULL;
}
void print_list(node* temp)
{
if (is_empty(temp)==false)
{
cout<<"here temp(head)"<<temp->next<<endl;
while(temp!=NULL)
{
cout<<temp->x<<endl;
temp = temp->next;
}
}
}
Print function print first element because you have just one node in the Linked List! Actually the mistake is present in add_element(node*) function, you overwrite address of head node with new node (so having memory leak) as I marked below:
node* add_element(node* current)
{
node* temp;
temp = new node; <---" You allocated memory"
temp->next = NULL; <---" Set next NULL"
cout<< "enter element" << endl;
cin>> temp->x; <---" Assign a value in new node"
// Replace below two line with suggested
current = temp; <---"MISTAKE: Overwrite first node"
"temp next is NULL so losing address of other nodes"
return current; <--- "return first node"
}
Next of new node (so first node) is NULL hence the print function prints only first node's value.
Suggestion:
You should Correct as follows to add new node as a first node in linked list:
temp -> next = current; // new nodes next if present first node
return temp; // new code becomes first node
Be careful current should be NULL initially.
With my suggestion in add_element() function also change the for loop code in main() as follows:
for(int i=0; i < 5; i = i + 1){
current = add_element(current);
}
head = current;
And check the working code at Codepade (instead of user input I added value using y = 100 variable).
Edit To append new node:
You need to check whether new node is first node of not (read comments).
// returns first node address in linked list = head
node* add_element(node* head){
node *temp, *new_nd;
// Create new node
new_nd = new node;
new_nd->next = NULL;
cout<<"enter element"<<endl;
cin>>new_nd->x;
// Is new node is the first node?
if(!head)
return new_nd;
// move to last
temp = head;
while(temp->next) temp = temp->next;
// add new node at last
temp->next = new_nd;
// return old head
return head;
}
Also simply main() as below:
int main(){
node *head = NULL;
for(int i = 0; i < 5; i = i + 1){
head = add_element(head);
}
print_list(head);
}
check this working code.
Your problem is here:
node* add_element(node* current)
{
node* temp; //You created a new node
temp=new node; //You allocated it here
temp->next=NULL; //You set its next property to null
cout<<"enter element"<<endl; //
cin>>temp->x;
current=temp; //This should be current->next = temp. You are overwriting it!
return current; //And now you are returning essentially the temp object that
//You created and you set its next property to NULL
}
You are assigning the node you created in temp = new node to the current node that was passed in. What you want to do is assign the node you just created to the current node's next property. It should be current->next = temp
head->next is NULL because you set it so in add_element(). To have a linked list, you should set current->next = temp.
As you're using C++, you might consider using std::list instead of implementing your own linked list.
if (current==NULL)
{ current=add_element(current);
head=current;
}
else
{ current->next=add_element(current);
current=current->next;
}
The correct code.
You have to make a small correction in the loop.
You have to add a new node and then make it point to the next of the current node.
so the simplified code is current->next=add_element(current)
and then make current point to the new current.