As in the title my code gives the said warning and mashes up the memory references.
I was tasked with using nested classes in C++. This code is mostly my code for linked lists from a previous C application but remade for C++.
I ve searched on the internet about said NULL exception and I can t figure it out.
I ll post the code and hope someone can give me some tips.
In the various links and tips on the internet it says that the pointer I am pointing to is referencing to a NULLptr, and that it can t accces a NULL address.
Tried to review it in various forms but it doesn t work.
Header
#ifndef LIST_H
#define LIST_H
#include <iostream>
#include <math.h>
using namespace std;
class List
{
private:
class Node {
public:
int data;
Node* next;
Node() {
this->data = NULL;
this->next = NULL;
}
};
Node* head;
public:
List();
void insertList(int data);
void deleteFromList(int data);
void deleteLowerThan(int lower);
void calculateArithmetic();
void showList();
};
#endif
Cpp file
List::List() {
this->head = NULL;
}
void List::insertList(int n) {
Node* new_node = new Node();
new_node->data = n;
new_node->next = head;
head = new_node;
}
void List::deleteFromList(int n) {
Node* temp = head;
Node* prev = NULL;
if (temp != NULL && temp->data == n) {
head = temp->next;
return;
}
while (temp->data != n && temp != NULL) {
prev = temp;
temp = temp->next;
}
if (temp == NULL) return;
prev->next = temp->next;
}
void List::deleteLowerThan(int n) {
Node* temp = head;
while (temp != NULL) {
if (temp->data < n) {
deleteFromList(temp->data);
}
else {
temp = temp->next;
}
}
}
void List::showList()
{
Node* temp = head;
while (temp != NULL)
{
cout << temp->data << " ";
temp = temp->next;
}
}
Driver
int main() {
List lista;
lista.insertList(2);
lista.insertList(4);
lista.insertList(6);
lista.insertList(8);
lista.insertList(3);
lista.insertList(1);
lista.insertList(-4);
lista.showList();
lista.deleteFromList(4);
lista.showList();
lista.deleteFromList(8);
lista.showList();
lista.deleteFromList(6);
lista.showList();
lista.deleteLowerThan(3);
lista.showList();
return 0;
}
The problem lies in your deleteFromList function, with this code:
while (temp->data != n && temp != NULL) {
//...
Here, you are trying to check the value of temp->data before you have verified whether or not temp is NULL. Thus, you will, at some point (when you're at the end of the list, and temp is NULL be dereferencing a null pointer - which ain't good!
Instead, just invert the order of the comparisons:
while (temp != NULL && temp->data != n) {
//...
This way, as soon as temp is NULL, the comparison's result will be fully known (see short circuiting), temp->data will not be evaluated, and the loop will stop running.
As pointed out by Adrian and Andy, this line causes temp to be dereferenced before you check if it's NULL:
while (temp->data != n && temp != NULL)
so, just check that it's not NULL first, then dereference it.
Other mentionable problems are the memory leaks. You should have exactly one delete for each new (unless you surrender the pointer to a smart pointer that will do delete for you).
void List::deleteFromList(int n) {
Node* temp = head;
Node* prev = head; // set this if you need to delete head
if(temp != nullptr && temp->data == n) {
head = prev->next;
delete prev; // you forgot this
return;
}
while(temp != nullptr && temp->data != n) {
prev = temp;
temp = temp->next;
}
if(temp == nullptr) return;
prev->next = temp->next;
delete temp; // you forgot this
}
You also need to implement a destructor in List to delete all the nodes in the List when it is destroyed.
A trickier bug is in your deleteLowerThan() function. You iterate over the nodes in your list and call deleteFromList() which will delete the very node you are currently on. In the next iteration, you use the same node pointer in if (temp->data < n) { causing undefined behaviour. In my case, the program seemed to just hang forever.
One possible fix:
void List::deleteLowerThan(int n) {
Node* temp = head;
int tmpdata;
while(temp != nullptr) {
tmpdata = temp->data; // save the nodes data
temp = temp->next; // step before you delete
if(tmpdata < n) {
deleteFromList(tmpdata);
}
}
}
Related
This is a basic function that takes an iterator position and deletes the node in this position but it gives me a runtime error. what am i doing wrong?
iterate erase(iterate position)
{
iterate i;
Node<T>* temp = head;
if (head == NULL) {
cout << "empty list" << endl;
}
else if (position.pointer == head) {
head = temp->next;
temp->next->previous = NULL;
delete position.pointer;
}
else {
while (temp != NULL) {
if (temp == position.pointer->previous) {
temp->next = position.pointer->next;
temp->next->previous = temp;
i.pointer = temp->next;
delete position.pointer;
return i;
}
}
}
Your function is lacking adequate return statements. There are multiple flows that can cause the function to exit, but only one of them has a return statement. So the return value will largely be indeterminate, causing undefined behavior for any caller that tries to use the return value.
In any case, your while loop iterates forever, because you are not updating temp on each iteration of the loop. You also have a NULL pointer dereference if position is pointing at the last node in the list, as you are not checking the new temp->next for NULL before accessing temp->next->previous.
But, you really don't need the while loop at all. The thing about a double-linked list is that, given any node in the list, you have direct access to the nodes that are surrounding it on both sides. So there is no need to iterate the list hunting for nodes.
Try something more like this instead:
iterate erase(iterate position)
{
Node<T> *temp = position.pointer;
if (!temp) return end();
Node<T> *next = temp->next;
Node<T> *previous = temp->previous;
if (next) next->previous = previous;
if (previous) previous->next = next;
if (temp == head) head = next;
//if (temp == tail) tail = previous;
delete temp;
iterate i;
i.pointer = next;
return i;
}
Alternatively:
iterate erase(iterate position)
{
Node<T> *temp = position.pointer;
if (!temp) return end();
Node<T> *dummy; // <-- only if no tail ...
Node<T> **previous = (temp->next) ? &(temp->next->previous) : &dummy/*&tail*/;
Node<T> **next = (temp->previous) ? &(temp->previous->next) : &head;
*previous = temp->previous;
*next = temp->next;
delete temp;
iterate i;
i.pointer = *next;
return i;
}
I am trying to delete a node from a linked list using this function:
void del_node(int del_data)
{
node* temp = NULL;
node* trail = NULL;
node* del_ptr = NULL;
temp = head;
trail = head;
while (temp != NULL && temp->data != del_data)
{
trail = temp;
temp = temp->next;
}
if (temp != NULL) {
del_ptr = temp;
temp = temp->next;
trail->next = temp;
delete(del_ptr);
}
}
It seems like it deletes it fine until i print the linked list using this:
void print()
{
node* temp = NULL;
temp = head;
while (temp != NULL)
{
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
and it starts outputting seemingly random numbers, can anybody help me with this, really confused as this code comes from a tutorial.
Your algorithm doesn't manage the head pointer correctly whatsoever. Any changes that ultimately should modify the head pointer don't, and that's a huge problem. A pointer to pointer algorithm not only solves this problem, it also delivers a considerably more succinct solution:
void del_node(int del_data)
{
struct node **pp = &head;
while (*pp && (*pp)->data != del_data)
pp = &(*pp)->next;
if (*pp)
{
node *tmp = *pp;
*pp = tmp->next;
delete tmp;
}
}
This will work for any list condition including:
An empty list. i.e. head is null.
A single-node list. If the value matches head->data it will properly delete and reset the node pointer.
A multi-node list. The first matching node will be removed, and it will properly fix up the head node pointer if that was the matching location.
All of the above, in cases where there is no matching node, the list remains unchanged.
Fulfilling all of that in such a short algorithm + implementation is beneficial.
I'll comment on your code inline:
void del_node(int del_data)
{
node* temp = NULL;
node* trail = NULL;
node* del_ptr = NULL;
temp = head;
trail = head;
// This is fine, but recommend you use nullptr instead of NULL.
// This will find the first instance of data matches del_data,
// But if you are trying to delete all instances of del_data,
// You'll need to do this a little differently.
while (temp != NULL && temp->data != del_data)
{
trail = temp;
temp = temp->next;
}
// This if is fine, but see previous comment about using nullptr
// instead of NULL.
if (temp != NULL) {
del_ptr = temp;
temp = temp->next;
// Problematic: What if trail is null?
trail->next = temp;
delete(del_ptr);
}
}
Your code isn't bad. I wouldn't have written exactly like this, but I'm going to replace your if-statement:
if (temp != nullptr) {
// If trail is nullptr, then we're deleting from the head
if (trail == nullptr) {
head = temp->next;
}
else {
trail->next = temp->next;
}
delete(temp);
}
There's no need for the temporary. Just point around temp as you see in the if-else block and then delete temp.
I was tasked with creating functions to add and delete nodes in a linked list given input data as an int and the char for with function to call. I'm not sure what I'm doing wrong. The only error I was given was: Exited with return code -11 (SIGSEGV). And a compiler method: main.cpp: In function ‘void listInsertValue(ListNode*&, ListNode*&, int)’:
main.cpp:111:23: warning: ‘toGoAfter’ may be used uninitialized in this function [-Wmaybe-uninitialized]
111 | toGoAfter->next = head;
Any help is appreciated. Thanks!
#include <iostream>
using namespace std;
struct ListNode
{
int data;
ListNode* next;
};
void listRemoveAfter(ListNode*&, ListNode*&, ListNode*);
void listPrepend(ListNode*&, ListNode*&, ListNode*&);
void listDeleteValue(ListNode*&, ListNode*&, int);
void listInsertValue(ListNode*&, ListNode*&, int);
void listInsertAfter(ListNode*&, ListNode*&, ListNode*, ListNode*);
int main()
{
ListNode *head = nullptr, *tail = nullptr;
ListNode *temp;
char choice;
int val;
//Write a main like you did in the previous lab
char command;
int number;
cin >> command;
while(command != 'Q')
{
if(command == 'I')
{
cin >> number;
listInsertValue(head,tail,number);
}
else
{
cin >> number;
listDeleteValue(head,tail,number);
}
cin >> command;
}
ListNode* current;
current = head;
while (current != nullptr)
{
cout << current->data << " ";
current = current->next;
}
cout << endl;
return 0;
}
//From previous lab - already complete
void listPrepend(ListNode*& h, ListNode*& t, ListNode*& n)
{
if (h == nullptr)
{
h = n;
t = n;
}
else
{
n->next = h;
h = n;
}
}
//From book, write yourself using the book code in 17.6 as a starting point
void listInsertAfter(ListNode*&head, ListNode*&tail, ListNode* curNode, ListNode* newNode)
{
if (head->next == nullptr)
{
head= newNode;
tail = newNode;
}
else if (curNode->next == tail)
{
tail->next = newNode;
tail = newNode;
}
else
{
newNode->next = curNode;
curNode->next = newNode;
}
}
//This function is mostly written, but you will need to add some code near the TODOs to complete the algorithm from the slides
void listInsertValue(ListNode*& head, ListNode*& tail, int val)
{
ListNode* toGoAfter, *newNode;
//TODO - create a new ListNode (newNode) with a data value of val (3 lines of code)
newNode = new ListNode;
newNode->data = val;
newNode->next = nullptr;
//TODO - check whether the list is empty in the if condition
if (head == nullptr)
{
listInsertAfter(head, tail, nullptr, newNode);
}
//TODO - use the else if to check whether the the value passed in is smaller than the value in the head
else if (head->data > val) //need to add to beginning of the list
{
listPrepend(head, tail, newNode);
}
else //need to add somewhere else in the list
{
//TODO - set toGoAfter to point to the head
toGoAfter->next = head;
//loop to find the location to insert the value
while (toGoAfter->next != nullptr && toGoAfter->next->data < val)
{
//TODO - set toGoAfter to point to the node after toGoAfter, like is done in traversals
toGoAfter = toGoAfter->next;
}
//We have found the location, so we can insert
listInsertAfter(head, tail, toGoAfter, newNode);
}
}
//modify
void listDeleteValue(ListNode* &head, ListNode*& tail, int val)
{
ListNode *temp;
//TODO - check if list is not empty in if condition
if (head->next == nullptr)
{
// TODO - check if value of head matches val passed in
if (head->data == val)
listRemoveAfter(head, tail, nullptr);
}
else
{
//loop searches for value to delete in node following temp
//TODO - set temp to point to the head
temp->next = head;
while (temp->next != nullptr && temp->next->data != val)
{
//TODO - set temp to point to the node after temp, like is done in traversals
temp = temp->next;
}
//TODO - make sure a node exists after temp, meaning the value to delete was found
if (temp->next != nullptr)
listRemoveAfter(head, tail, temp);
}
}
//From book, write yourself using the book code in 17.7 as a starting point
//Also add to the book's code, the code to delete nodes from memory
void listRemoveAfter(ListNode* & head, ListNode*& tail, ListNode* curNode)
{
ListNode *sucNode, *toDelete;
if (curNode->next == nullptr && head->next != nullptr)
{
sucNode = head->next;
head->next = sucNode;
if (sucNode->next == nullptr)
{ // Removed last item
tail->next = nullptr;
toDelete = head;
}
}
else if (curNode->next != nullptr)
{
sucNode = curNode->next->next;
curNode->next = sucNode;
if (sucNode-> next == nullptr)
{ // Removed tail
tail->next = curNode;
toDelete = curNode->next;
}
}
delete toDelete; //needed after the if/else if to remove the deleted node from memory
}
For most part you are not handling the case when there ia no element in the list. While inserting handle 4 use cases
Head==nullptr => head =newNode;
head->data > val
Tail->data < val
else case : insert in middle
Generic mistake: accessing ptr-> next, when ptr is nullptr
In general you want to use a debugger and any access to a memory 0x0 (nullptr) will start resolving your issues. ie head is 0x0 and you are doing operationa like head->data ==val
I am teaching myself data structures in C++ and my current challenge is to create, and merge, two linked lists. However, Microsoft Visual Studio throws the following error:
Debug Assertion Failed! Program: LinkedList\Debug\LinkedList.exe File: minkernel\crts\ucrt\src\appcrt\heap\debug_heap.cpp Line: 904 Expression: _CrtlsValidHeapPointer(block)
However, it seems to work fine in Wandbox: Source code in Wandbox Online Compiler Where does it go wrong?
This is the source code:
#include <iostream>
#include <cstdlib>
class Node {
public:
int data;
Node* next;
};
class LinkedList {
public:
LinkedList() {
head = nullptr;
}
~LinkedList() {
Node* temp = head;
while (head) {
head = head->next;
delete temp;
temp = head;
}
};
void addNode(int value);
void display();
void merge(LinkedList& list2);
private:
Node* head;
};
void LinkedList::addNode(int value) {
Node* newnode = new Node();
newnode->data = value;
newnode->next = nullptr;
if (head == nullptr) {
head = newnode;
} else {
Node* temp = head; // head is not NULL
while (temp->next != nullptr) {
temp = temp->next; // go to end of list
}
temp->next = newnode; // linking to newnode
}
}
void LinkedList::display() {
if (head == nullptr) {
std::cout << "List is empty!" << std::endl;
} else {
Node* temp = head;
while (temp != nullptr) {
std::cout << temp->data << " ";
temp = temp->next;
}
std::cout << std::endl;
}
}
void LinkedList::merge(LinkedList& list2) {
Node* node = new Node();
node->next = nullptr;
Node* temp = node;
Node* head1 = head;
Node* head2 = list2.head;
while (head1 != nullptr && head2 != nullptr) {
if (head1->data <= head2->data) {
temp->next = head1;
temp = temp->next;
head1 = head1->next;
} else {
temp->next = head2;
temp = temp->next;
head2 = head2->next;
}
}
while (head1 != nullptr && head2 == nullptr) {
temp->next = head1;
temp = temp->next;
head1 = head1->next;
}
while (head2 != nullptr && head1 == nullptr) {
temp->next = head2;
temp = temp->next;
head2 = head2->next;
}
temp = temp->next;
delete temp;
head = node->next;
}
int main() {
LinkedList list;
list.addNode(1);
list.addNode(2);
std::cout << "Linked List Data: " << list.display() << std::endl;
LinkedList list2;
list2.addNode(3);
list.merge(list2);
list.display();
return 0;
}
That MSVC error indicates that you're doing something bad with memory. In this case it seems you're deleting memory twice. Freeing a pointer twice is Undefined Behavior and compilers/runtimes are not required to diagnose the problem.
Your merge seems to be expecting sorted lists, but addNode does not enforce this. Also, once that merge is done, the nodes of list2 will be contained in both the returned list and the original list2. When the LinkedList destructor runs you will (try to) delete those nodes twice. The Microsoft Compiler in Debug builds can tell you about these problems.
There are also issues with memory leaks (e.g., the node allocated in merge is not freed).
The Expression: _CrtIsValidHeapPointer(block) indicates that memory has corrupted, possibly due to writing past the end of a buffer or writing past the end of a class because the writer assumes the class is larger than was allocated (like when it is expecting a derived class and gets a base class, or object of a different class).
Please open Debug->Windows->Exception Settings, In the Exception Settings window, expand the node for a category of exceptions -> Common Language Runtime Exceptions( meaning .NET exceptions), and select the check box for a specific exception within that category System.AccessViolationException. You could also select an entire category of exceptions if you don't know which exception to choose. And then you could see the initial problem.
For more information about how to manage exceptions, please refer to this document below:
https://learn.microsoft.com/zh-cn/visualstudio/debugger/managing-exceptions-with-the-debugger?view=vs-2019&redirectedfrom=MSDN
I have a function and it is suppose to organize a dictionary of stemmed words. I have a function call inserted then suppose to place it in the right alphabetical order. Adding to the front and middle of the list works, but adding to the back doesn't. I've looked at several sources and I can't tell what's wrong.
void dictionary::insert(string s) {
stem* t = new stem;
t->stem = s;
t->count =0;
t->next = NULL;
if (isEmpty()) head = t;
else {
stem* temp = head;
stem* prev = NULL;
while (temp != NULL) {
if (prev == NULL && t->stem < temp ->stem) {
head = t;
head->next = temp;
}
prev = temp;
temp = temp->next;
if(t->stem > prev->stem && t->stem < temp->stem ){
prev->next =t;
t->next=temp;
}
}
if(temp == NULL && t->stem > prev->stem){
prev->next=t;
}
}
}
The statement if(temp->next=NULL) does not result in a boolean but rather an assignment. This is why the insert to the end of the list doesn't appear to work.
if (temp->next=NULL) {
prev->next = t;
}
Note the usage of a single equal. The effect of this is to set the temp->next to NULL and then evaluate if (NULL) witch will be always false. You should use ==.
This will probably do the job: (sorry, I don't have a compiler right now to test it)
#include <string>
struct node;
struct node
{
node* next;
std::string value;
};
node* head = NULL;
void insert(const std::string& word)
{
node* n = new node;
n->value = word;
node* temp = head;
node** tempp = &head;
while (true)
{
if (temp == NULL or temp->value > word)
{
n->next = temp;
*tempp = n;
return;
}
temp = temp->next;
tempp = &temp->next;
}
}