I'm trying to create a linked list, but I have a problem about memory access. I debug the code, see where it gives error, but cannot solve it. With using 'Add watch', can see the next has unable to read memory error.
struct Node
{
string Name;
Node* next;
};
struct LinkedList
{
Node* head = NULL;
bool isX = true;
};
LinkedList* initX(string Arr)
{
LinkedList* link = new LinkedList;
for (int i = 0; i < 15; i++)
{
Node* temp = new Node;
temp->Name = Arr[i];
Node* ptr = new Node;
ptr = link->head;
if (link->head != NULL)
{
while (ptr->next)
{
ptr = ptr->next;
}
ptr->next = temp;
temp->next = NULL;
}
else
link->head = temp;
}
return link;
}
Unhandled exception at 0x008E8AF7 in ...exe: 0xC0000005: Access violation reading location 0xCDCDCDE9.
How can I solve it?
After you set link->head to temp in the else part of your if statement, you don't set temp->next to NULL, thus making any use of temp->next as if it had a value in undefined behavior. Add this to your else part:
else {
link->head = temp;
temp->next = NULL; // or nullptr
}
It would actually be better if you moved both temp->next = NULL, made them into one, and put it as the last statement in the for loop. That why you don't have to do the same thing for both conditions.
Related
I need to implement a doubly linked list in c++ for a small animation running on console. The linkedlist stores clouds and then they move through the console and as each cloud hits the end of screen, it needs to be deleted from linked list. As the cloud hits the end, it has a variable called alive which is set to false so it can be deleted.
I can't upload the full game code, but I have recreated the problem in dummy code by creating sample clouds where some of them have alive = true and alive = false. I have also updated the previous and next nodes of the cloud to be deleted but I still get an error:
Exception thrown: read access violation. temp was 0xFFFFFFFFFFFFFFFF.
Code below (include statements removed for simplicity)
Test.cpp
int main() {
Cloud* a = new Cloud('a');
a->alive = false;
Node* a1 = new Node(a);
Cloud* b = new Cloud('b');
b->alive = false;
Node* b1 = new Node(b);
LinkedList list;
list.Insert(a);
list.Insert(b);
Node* temp = list.head;
while (temp != nullptr) {
if (temp->data->alive == false) list.Delete(temp); // throws exception after deleting a single node.
temp = temp->next;
}
return 0;
}
LinkedList.cpp delete function
void LinkedList::Delete(Node* del) {
if (del == head) {
OutputDebugStringA("Cloud in head");
Node* temp = head;
head = head->next;
head->prev = nullptr;
delete temp;
return;
}
else {
Node* temp = head;
while (temp != tail->next) {
if (temp == del) {
if (temp->next != nullptr) {
OutputDebugStringA("Cloud in mid");
temp->prev->next = temp->next;
temp->next->prev = temp->prev;
break;
}
else {
OutputDebugStringA("cloud at tail");
tail = temp->prev;
tail->next = nullptr;
break;
}
}
temp = temp->next;
}
delete temp;
temp = nullptr;
}
}
Node.cpp
#include "Node.h"
#include <iostream>
using namespace std;
Node::Node() {
this->data = nullptr;
}
Node::Node(Cloud* data) {
this->data = data;
}
Someone please point out where am I going wrong. Thanks
if (temp->data->alive == false) list.Delete(temp); // throws exception after deleting a single node.
temp = temp->next;
Here, temp gets passed into the Delete() method. Afterwards temp gets set to temp->next.
In Delete():
delete temp;
temp = nullptr;
The object referenced by the passed-in temp pointer (here, this temp, by the virtue of the preceding logic, is the same pointer that gets passed in) gets deleted.
After returning, temp->next references a deleted object.
This is at least one confirmed instance of undefined behavior in the shown code. This may or may not be the only bug.
As it's been pointed out to you in comments, this overall Delete() logic is fundamentally flawed. It should not involve any kind of iteration, for a doubly-linked list. You will end up fixing this bug while rewriting Delete() from scratch (which includes rethinking how Delete() itself gets called, because after it returns temp is no longer usable for anything).
As #John Zwinck and #Sam Varshavchik pointed out that the implementation of delete method was flawed and temp became useless after the Delete function returned.
I fixed it by using another temp pointer and fixing the delete method to be O(1).
Delete Method
void LinkedList::Delete(Node* del) {
if (del == head) {
head = head->next;
head->prev = nullptr;
}
else if (del == tail) {
tail = del->prev;
tail->next = nullptr;
}
else {
del->prev->next = del->next;
del->next->prev = del->prev;
}
delete del;
}
Node deletion
Node* temp = cloud_list.head;
Node* next;
while (temp != nullptr) {
next = temp->next;
if (temp->data->alive == false) {
cloud_list.Delete(temp);
}
temp = next;
}
The deletion now works fine.
I'm just getting back into coding. It's been a few years. I can not figure out why this is throwing a nullptr access violation. I've condensed it into a single line of code. The violation is thrown when I try to set my second entry (newNode's pLast pointer) to head.
I'm trying to create a doubly linked list with a bubble sort based off of searches performed (aka countVar). Any help would be great.
#include <iostream>
#include <stdlib.h>
using namespace std;
//build class that has a private function to inc count.
class LinkedListCount {
private:
struct CountNode {
int data;
int countVar; //Make the variable "countVar" private to protect integrity.
CountNode* pNext = NULL;
CountNode* pLast = NULL; //Needed for bubbling back through list.
};
//Keep track of head
CountNode* head;
CountNode* current;
CountNode* temp;
public:
//Constructor Function (Set default values for head, current, and temp)
LinkedListCount() {
head = NULL;
current = NULL;
temp = NULL;
}
void AddNode(int dataIn) { //Addnode Function
//Create and populate list.
CountNode* newNode = new CountNode;
newNode->pNext = NULL;
newNode->pLast = NULL;
newNode->data = dataIn;
temp = head;
newNode->countVar = 0;
if (temp != NULL) { //We already have data entery.
if (temp->pNext == NULL) {
newNode = temp->pNext;
newNode->pLast = head; //****THIS IS WHERE ACCESS VIOLATION OCCURES
}
//Set variables with the understanding that the head is the only data point.
else {
current = temp->pNext; //Set it equal to head.
}
while (current->pNext != NULL) {//This could be eliminated with keeping track of a tail.
current = current->pNext; //Attach this to the end of the list.
}
current->pNext = newNode; //And newMode->pNext = to Null so next time I add data I'll get to the end of the list.
newNode->pLast = current;
}
else if (head == NULL) {
head = newNode;
}
}
};
void addNodes(LinkedListCount &DataList) { //Populates list.
for (int i = 0; i < 20; i++) {
DataList.AddNode(i);
}
}
int main(void)
{
addNodes(DataList);
}
if (temp->pNext == NULL) { // temp->pNext is NULL
newNode = temp->pNext; // newNode is now NULL too
newNode->pLast = head; // attempt to use pLast of NULL
}
I've put comments in your code to see why you have the access violation.
I am trying to delete a node from the end of the doubly linked list,but i am getting:
segmentation fault
i have added different functions to add the node, from beginning , from end , and at any position.I checked the insertion of nodes,its working fine,the DLL is displayed correctly,but when it comes to deleting function,it gives segmentation fault.
struct Node {
Node* left;
Node* right;
int data;
};
Node* head = NULL;
void insertion_At_End(int element) {
Node* ptr = head;
Node* temp = new Node;
temp->left = temp->right = NULL;
temp->data = element;
if(head==NULL) {
head = temp;
} else {
while(ptr->right!=NULL) {
ptr = ptr->right;
}
temp->left = ptr->right;
ptr->right = temp;
}
}
void insertion_At_Beg(int element) {
Node* ptr = head;
Node* temp = new Node;
temp->left = temp->right = NULL;
temp->data = element;
if(head==NULL) {
head = temp;
} else {
temp->right = ptr;
ptr->left = temp;
head = temp;
}
}
void insertion_At_Pos(int element , int position , int length) {
Node* ptr;
Node* temp = new Node;
temp->left = temp->right = NULL;
temp->data = element;
int counter = 1;
if(position==1) {
insertion_At_Beg(element);
}
else if(position==length) {
insertion_At_End(element);
}
else {
ptr = head;
while(counter!=(position-1)) {
ptr = ptr->right;
counter++;
}
temp->right = ptr->right;
ptr->right->left = temp;
temp->left = ptr;
ptr->right = temp;
}
}
void deletion_At_End() {
Node *ptr = head;
while(ptr->right!=NULL) {
ptr = ptr->right;
}
ptr->left->right=NULL;
delete ptr;
}
I get the error if i have only one element in the list. When you have only one element in the list you can not set what it is in its left's right pointing to NULL because it does not exist! This works for me:
void deletion_At_End() {
Node *ptr = head;
while(ptr->right!=NULL) {
ptr = ptr->right;
}
if(ptr->left == NULL){
delete ptr;
}
else{
ptr->left->right=NULL;
delete ptr;
}
}
I am a beginner learning c++, and currently making a singly linked list. I have faced some problems and I thought for a very long time, searched a lot but still do not have an answer for this code so I am begging for some help..
So this is my linked.h
template <class T>
class Node {
public:
T data;
Node<T>* next;
};
template <class T>
class List {
private:
Node<T> *head;
public:
List() : head(NULL) {};
~List() {
Node<T>* ptr, tmp;
for(ptr = head->next; ptr == NULL; ptr = head->next) {
delete ptr;
}
}
List(T* arr, int n_nodes) {
head = NULL;
Node<T> *tmp = head;
for(int i = 0; i < n_nodes; i++) {
Node<T>* node = new Node<T>;
node->data = arr[i];
if(head == NULL) {
head->next = node;
tmp = node;
}
else {
tmp->next = node;
node->next = NULL;
tmp = node;
}
}
}
friend std::ostream& operator<<(std::ostream& out, List<T>& rhs) {
Node<T>* cur = rhs.head;
out << cur;
while(cur != NULL) {
if(cur->next != NULL) {
out << cur->data << ", ";
cur = cur->next;
}
else
out << cur->data << " ";
}
return out;
}
};
and this is my main.cc file.
#include <iostream>
#include "linked.h"
int main() {
int array[5] = {12, 7, 9, 21, 13};
List<int> li(array, 5);
std::cout << li;
return 0;
}
I keep on getting segmentation fault when running the constructor and I don't get why. Where am I making a mistake? Any help would be appreciated!
You could cover the issue with a pointer to pointer:
List(T* arr, int n_nodes)
{
Node<T>** tmp = &head; // tmp *pointing* to uninitialized(!) head pointer
for(int i = 0; i < n_nodes; i++)
{
Node<T>* node = new Node<T>();
node->data = arr[i];
// now the trick:
*tmp = node; // !!!
// you now have assigned the new node to whatever pointer
// the tmp pointer points to - which initially is - guess - head...
// but we now need to advance!
tmp = &node->next;
}
// tmp now points to latestly created node's next pointer
// (or still head, if no nodes where created because of n_nodes == 0)
// be aware that this one still is not initialized! so:
*tmp = nullptr;
}
Your destructor necessarily fails, too:
Node<T>* ptr, tmp;
for(ptr = head->next; ptr == NULL; ptr = head->next)
{
delete ptr; // you delete ptr, but advancing (ptr = head->next)
// is done AFTERWARDS, so you'd access already deleted memory
// undefined behaviour
}
Additionally, you don't delete the head node! And if head is nullptr, you again have undefined behaviour.
Try it this way:
while(head)
{
Node<T>* tmp = head; // need a copy of pointer
head = head->next; // need to advance BEFORE deleting
delete tmp; // now can delete safely
}
I've written code to insert elements into a circular doubly linked list and to display these elements. I'm supposed to also be able to delete the tail node from the the list, as well as search the list for a specific element.
This is my working code for add and print:
void Circular_DLList::add_to_tail(int a)
{
DLLNode *temp = new DLLNode;
temp->info = a;
if (is_empty()) {
tail = temp;
temp->next = tail;
temp->prev = tail;
}
else {
temp->next = tail->next;
temp->prev = tail;
tail = temp;
tail->prev->next = temp;
}
}
void Circular_DLList::print_list()
{
DLLNode *ptr;
ptr = tail->next;
do {
cout<< ptr->info << endl;
ptr = ptr->next;
}
while(ptr != tail->next);
}
No matter what I write for the delete_from_tail function, it causes a segmentation fault:11. This is my attempt for the function (which throws the error).
int Circular_DLList::delete_from_tail()
{
int a = tail->info;
if(tail == tail->next) {
delete tail;
tail = NULL;
}
else {
tail = tail->prev;
delete tail->next;
tail->next = NULL;
}
return a;
}
Any advice as to how to fix this would be fantastic. I've tried debugging but I can't seem to figure out the issue or where exactly it's even related to.
Thanks
The issue is pretty obvious if you look at it closely. Your delete function is breaking the circular chain of the Link list. How so? See your delete function below:
int Circular_DLList::delete_from_tail()
{
int a = tail->info;
DLLNode *temp;
if(tail == tail->next) {
delete tail;
tail = NULL;
}
else {
tail = tail->prev;
delete tail->next;
tail->next = NULL;
}
return a;
}
In the else-condition you are setting tail->next = NULL which is actually the bug and hence breaks the chain. So when print is called it assumes that circular chain is intact and hence accidently tries to access a NULL pointer which in turn leads to segmentation fault.
The Fix is very simple see the below code:
int Circular_DLList::delete_from_tail()
{
int a = tail->info;
if(tail == tail->next) {
delete tail;
tail = NULL;
}
else {
temp = tail;
tail = tail->prev;
tail->next = temp->next; // To maintain the circular chain
tail->next->previous = tail; // Since this element's previous also point to the node about to be deleted
delete temp;
temp = NULL;
}
return a;
}