C++ linked lists read access violation - c++

I'm new to C++ and I'm currently studying linked lists and I came upon this problem and I still can't find a solution.
This is how a basic node looks like.
struct node {
int data;
node *next;
};
I'm trying to swap the position of the first and the last node with this function.
void swap_first_and_last() {
node *temp = new node;
node *temp2 = new node;
temp->data = head->data;
temp->next = NULL;
temp2->next = head->next;
temp2->data = tail->data;
head = temp2;
tail = temp;
}
The error I'm getting is: Exception thrown: read access violation, this->tail was nullptr.
Can anyone explain what I'm doing wrong?

You havn't deleted head & tail.
Assuming tail is the last, there is somewhere a node::next pointing to it, and you didn't changed it to point to temp
What if the list is empty? you didn't checked if head or tail is null.
Edit added fixed method
void swap_first_and_last()
{
//if there is less than 2 nodes - finished.
if(!head || !tail || head==tail) return;
node *temp = new node;
node *temp2 = new node;
node *temp3;
temp->data = head->data;
temp->next = NULL;
temp2->next = head->next;
temp2->data = tail->data;
temp3 = head;
head = temp2;
delete temp3; //delete old head
temp3 = tail;
//find the tail previous
for(tail=head; tail->next!=temp3;tail=tail->next);
//make tail previous point to tail
tail->next = temp;
tail = temp;//now it will point to new tail...
delete temp3;//delete old tail
}
A better solution:
void swap_first_and_last()
{
node *temp;
//if there is less than 2 nodes - finished.
if(!head || !tail || head==tail) return;
for(temp=head; temp->next!=tail;temp=temp->next);
temp->next = head; //set tail precedor's next to point to head, prepere for head = tail
tail->next = head->next; //set tail's next to point head->next, prepere for head = tail
head = tail; //set tail as head
tail = temp->next; //set old head as tail
tail->next = NULL; // tail next is always null (was point to the 2nd).
}

// V----- where does tail get initialized?
temp2->data = tail->data;
When swap_first_and_last is called, but tail hasn't been initialized, just as the runtime says: you're going to have a bad time.
You can either -
Make sure that tail is initialized with a value before calling
swap_first_and_last
Check to see if tail is initialized before
trying to do any read access on it.
I think the latter is a better option.
if (head) {
temp->data = head->data;
}
if (tail) {
temp2->data = tail->data;
}
A question you should ask yourself - why don't I put this initialization in the constructor of node?

Your new to C++ so I understand this isn't particularly easy to grasp, but once you get the hang of it you will understand the comments above.
head and tail are pointers node *head; so you don't need to create copies of the objects that they point to.
head points to a block of memory that has the content (data = 42; next = tail) and tail points to a block of memory that holds (7 and null). You can copy head into temp and tail into temp2 and then copy them back into tail and head but why? What do you gain by creating copies of the memory blocks, apart from memory leaks? You don't care about the blocks of memory, you don't want to move them, you don't want to change them all you want to do is change which pointer points to which block of memory.
node* pTemp = head;
head = tail;
tail = head;
Unfortunately this breaks your list because now head->next = null so you just need to repair that:
pTemp = head->next; // Which should always be null.
head->next = tail->next;
tail->next = pTemp;
Now if you stick that in a little function that takes the two pointers as parameters you have a block of code that can switch any two given nodes in your list, meaning sorting your list becomes a lot easier.

Related

How to adjust head, tail pointers when building a LinkedList

I am making a simple implementation of LinkedList. My Trial:
#include<bits/stdc++.h>
using namespace std;
class ListNode
{
public:
ListNode* next;
int val;
ListNode(int x) : val(x), next(NULL) {}
};
int main()
{
ListNode* head = NULL;
ListNode* tail;
int data;
cout<<"Enter data. Enter -1 to terminate insertion"<<endl;
while(1)
{
cin>>data;
if(data != -1)
{
if(head == NULL)
{
head = new ListNode(data); // Returns the address of a new ListNode and stores it in head
tail = head->next; // tail now points to head's next
}
else
{
tail = new ListNode(data); // address of a new ListNode is in tail
tail = tail->next; // Tail now points to the new ListNode's next
}
}
else
break;
}
tail = NULL; // Tail ends with a NULL
while(head)
{
cout<<head->val<<" ";
head = head->next;
}
}
When I input 1, 2, 3: I expect the Linked List to be formed as 1->2->3->NULL.
However, the Linked List is always only the first element 1->NULL
I ran on the debugger and indeed, head->next is always NULL. But I dont understand why. I am specifically changing head's next to a new ListNode non-null address when I do tail = new ListNode(data), but apparently thats not happening. Where am I going wrong?
Here is the code: http://cpp.sh/6ardx
Problem: tail is always NULL.
How do you want to make the connection between tail and appended node to your list when tail is NULL ?
When list is empty and you create the first node, after inserting first node head and tail should point to the same node. Change
if(head == NULL)
{
head = new ListNode(data); // Returns the address of a new ListNode and stores it in head
tail = head->next; // tail now points to head's next
}
to
if(head == NULL)
{
tail = head = new ListNode(data); // Returns the address of a new ListNode and stores it in head
}
the second issue, when you add to the end of list you should update tail->next to point to the inserted node, so change
tail = new ListNode(data); // address of a new ListNode is in tail
tail = tail->next; // Tail now points to the new ListNode's next
to
tail->next = new ListNode(data); // address of a new ListNode is in tail
tail = tail->next; // Tail now points to the new ListNode's next

using temp variable to add node to end of linked list in c++

I am learning about linked lists and I have the following code but I do not understand it. What I am trying to grasp is the concept of how to use a temp variable to add a node to the end of a linked list. Could someone enlighten me as to what is happening?
I understand the first half but logic of the second half confuses me.
struct Node{
int data;
Node *next;
};
Node *head = NULL;
head = new Node;
head->next = NULL;
head->data = 97; // I understand up to here
Node *temp = head; //I do not understand this part on
temp->next = new Node;
temp = temp->next;
temp->next=NULL;
temp->data=50;
Node *temp = head
temp is now equal to head
temp->next = new Node;
intialize the next node
temp = temp->next;
now temp is moved to next node
temp->next=NULL;
this just means the last element of the linked list is just null
temp->data=50;
this is the value we need to append

Linked List pushback member function implementation

I am a novice programmer and this is my second question on Stack Overflow.
I am trying to implement a pushback function for my Linked List by using a tail pointer. It seems straightforward enough, but I have a nagging feeling that I am forgetting something or that my logic is screwy. Linked Lists are hard!
Here is my code:
template <typename T>
void LinkedList<T>::push_back(const T n)
{
Node *newNode; // Points to a newly allocated node
// A new node is created and the value that was passed to the function is stored within.
newNode = new Node;
newNode->mData = n;
newNode->mNext = nullptr;
newNode->mPrev = nullptr;
//If the list is empty, set head to point to the new node.
if (head == nullptr)
{
head = newNode;
if (tail == nullptr)
{
tail = head;
}
}
else // Else set tail to point to the new node.
tail->mPrev = newNode;
}
Thank you for taking the time to read this.
Your pointing the wrong mPrev to the wrong node. And you never set mNext of the prior tail node if it was non-null to continue the forward chain of your list.
template <typename T>
void LinkedList<T>::push_back(const T n)
{
Node *newNode; // Points to a newly allocated node
// A new node is created and the value that was passed to the function is stored within.
newNode = new Node;
newNode->mData = n;
newNode->mNext = nullptr;
newNode->mPrev = tail; // may be null, but that's ok.
//If the list is empty, set head to point to the new node.
if (head == nullptr)
head = newNode;
else
tail->mNext = newNode; // if head is non-null, tail should be too
tail = newNode;
}

Is it necessary to use 'new' to allocate a new pointer to a struct identical to a previously existing pointer to the same struct? If so, why?

I am writing a function that inserts a new element in a singly linked linked list.
The function accepts the *head to the list, the data to be put in the new element and the position in the l-list should be inserted at.
This is the link to the programming exercise in case I've not been clear enough.
The following code works perfectly -
/*
Insert Node at a given position in a linked list
head can be NULL
First element in the linked list is at position 0
Node is defined as
struct Node
{
int data;
struct Node *next;
}
*/
Node* InsertNth(Node *head, int data, int position)
{
//Takes head of list as input and returns it after inserting a new element
//with `data` at `position` in the l-list
Node *temp = new Node;
temp = head;
Node *newn = new Node;
newn->data = data;
if(position == 0){
newn->next = head;
return newn;
}
while(--position){
temp = temp->next;
}
newn->next = temp->next;
temp->next = newn;
return head;
}
However, I don't understand why I had to use Node *temp = new Node; temp = head;.
Why doesn't simply using Node *temp = head; work?
I'm only using the temp pointer to traverse the l-list so that I can preserve the location of the head when I return the final list.
Edit - I understand that Node *temp = head; is the way to go. This was how I originally programmed it too, but I forgot to mention that this is what's giving me a segfault. When I change it to Node *temp = new Node; temp = head; it works for all the testcases(including the ones where head is NULL).
Why must this seemingly absurd mem allocation seem to make it work is what I want to know.
The code you post above leaks.
Node *temp = new Node; temp = head;
This is no good.
Node *temp = head;
This is better.
There are other problems in your code; but your analysis that it was silly to new then immediately reassign the pointer is correct. Well spotted.
The answers that were posted before mine are both wrong, sure they Point out that your code leaks, but they didn´t check the rest of the code to see if it actually does what it is supposed to do. Your code is prone to Errors, because you don´t account for the head being NULL, which is clearly stated.
// Returns the new node inserted at the given Position inside the l-list
Node* InsertNth(Node *head, int data, int position)
{
Node *newn = new Node;
newn->data = data;
newn->next = 0;
// No head, return node right away
if(!head)
{
return newn;
}
// Exception - only case where head is not returned
else if(!position)
{
newn->next = head;
return newn;
}
// Create ´temp´ which is a pointer to the next node in the list
Node *temp = head;
// The function allows passing of a signed int, make sure we stay above 0
// as the previously while(--position) would go into an endless loop
// if a signed integer were passed on to the function
while(--position > 0)
{
// Just incase the input is bad, and position exceeds the size of the list
if(!temp->next)
{
break;
}
temp = temp->next;
}
// Now that we found the place in line, insert it between the temp and the next item
// in the list. Which may also be NULL
newn->next = temp->next;
temp->next = newn;
return head;
}
Now as you can see a few changes were made, the code earlier on didn´t account for head being NULL, and it didn´t properly set the member ´next´ to 0, which would lead to a Crash eventually if someone iterated over the supposedly null-terminated single-linked list.
Use of
Node *temp = new Node;
temp = head;
causes a memory leak. Memory allocated in the first line is lost. You need to use:
Node *temp = head;

Assigning a pointer address to a node

Following is my code for inserting a number in linked list if afterWhat is the number contained in head.
The error comes in the last line of the code where
head -> next = &temp;
The error is :
cannot convert Node** to Node* in assignment.
What I want to do is give the address of temp to the head.next so that head will point to temp.
void LinkedList::insertAfter(int toInsert, int afterWhat)
{
if(head->data == afterWhat)
{
Node* temp = new Node;
temp->next = head->next;
temp->data = toInsert;
head->next = &temp;
}
}
since temp is already a pointer,so you don't have to write &temp.
use head->next=temp;
You need
head->next = temp;
Type of temp is Node*, so type of &temp is Node**, so the compiler complains correctly.