I have a segmentation fault in my destructor but I'm not quite sure why. The code is for a map of key/value pairs which are stored in a Node array and chained to avoid collisions.
template<class V>
map<string, V>::~map()
{
for(unsigned int i = 0; i < SIZE; i++){
if(hashArray[i] != NULL){
Node* tmpNode = hashArray[i];
Node* currentNode = hashArray[i];
while(currentNode->next != NULL){
currentNode = currentNode->next;
delete tmpNode;
tmpNode = currentNode;
}
delete tmpNode;
}
}
delete [] hashArray;
}
The debugger points to this line but I'm sure I'm not going out of range.
while(currentNode->next != NULL){
Any other code can be provided if need be. thank you in advance for your help. :)
I cleaned it up a bit by getting rid of the duplicate hashArray[i]s. Also got rid of the duplicate checks for null:
template<class V>
map<string, V>::~map()
{
for(unsigned int i = 0; i < SIZE; i++) {
Node* currentNode = hashArray[i];
while(currentNode) {
Node* next = currentNode->next;
delete currentNode;
currentNode = next;
}
}
delete [] hashArray;
}
Related
I have been experimenting with binary trees. I am trying to build an expression tree with the below c++ code. but, i keep getting segmentation fault(core dumped) during runtime
#include<iostream>
#include<ctype.h>
#include<vector>
using namespace std;
struct tree{
char data;
tree *left=NULL;
tree *right=NULL;
tree *parent=NULL;
};
tree* newNode(char d)
{
struct tree* node = new tree;
//struct tree* nodep = &node;
node->data = d;
return node;
}
tree* parseTree(string expression)
{
vector<char> tokens;
for(int i = 0; i<expression.size(); i++)
tokens.push_back(expression[i]);
struct tree* currentNode = newNode(' ');
struct tree* prevNode = new tree;
for(int i = 0; i<tokens.size(); i++)
{
if(tokens[i]=='(')
{
currentNode->left = newNode(' ');
prevNode = currentNode;
currentNode = currentNode->left;
currentNode->parent = prevNode;
}
else if(tokens[i]=='+'||tokens[i]=='-'||tokens[i]=='*'||tokens[i]=='/')
{
currentNode->data = tokens[i];
prevNode = currentNode;
currentNode = currentNode->right;
currentNode->parent = prevNode;
}
else if(isdigit(tokens[i]))
{
currentNode->data = tokens[i];
prevNode = currentNode;
currentNode = currentNode->parent;
}
else if(tokens[i]==')')
{
prevNode = currentNode;
currentNode = currentNode->parent;
}
}
return currentNode;
}
int main()
{
string expression = "(3+(4*5))";
struct tree* root = parseTree(expression);
return 0;
}
I tried different things but i couldn't get rid of this error
what am i missing?
why do i get this error?
how to rectify this?
else if(tokens[i]=='+'||tokens[i]=='-'||tokens[i]=='*'||tokens[i]=='/')
{
currentNode->data = tokens[i];
prevNode = currentNode;
currentNode = currentNode->right;
currentNode->parent = prevNode;
}
No code ever sets any right to anything other than NULL. So in the last line, currentNode is NULL and you are dereferencing a NULL pointer.
Also, take a look here:
struct tree* prevNode = new tree;
This value is never used and when the value is changed, the tree you allocated here is leaked.
This part uses ->right, which was never set:
else if(tokens[i]=='+'||tokens[i]=='-'||tokens[i]=='*'||tokens[i]=='/')
{
currentNode->data = tokens[i];
prevNode = currentNode;
currentNode = currentNode->right;
currentNode->parent = prevNode; // SEGFAULT
}
So you are trying to write to address 0 + some offset, which you are not allowed to.
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'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.
So I'm working on a project using linked lists. The program basically takes in numbers until -999 is inputted and then does operations on it. The two operations I am having problems with are deleteAll, where all the same values are deleted from the list, and deleteSmallest, where the smallest value in the list is deleted. The code that calls both functions is as follows:
int num;
cout << "Enter a number you would like deleted from the whole list: ";
cin >> num;
uList.deleteAll(num);
cout << "New list: " << uList << endl;
uList.deleteSmallest();
cout << "After deleting the smallest number, the list now is: " << uList << endl;
The code for deleteAll is as follows:
template <class Type>
void UnorderedLinkedList<Type>::deleteAll(const Type& deleteItem)
{
NodeType<Type>* curr;
NodeType<Type>* p = NULL;
NodeType<Type>* q = NULL;
curr = first;
if(first == NULL)
throw std::runtime_error("Cannot delete from an empty list");
else
{
for(int i = 0; i < count; i++)
{
if(curr->info == deleteItem)
{
p = curr;
q = p->link;
p->link = q->link;
delete q;
}
curr = curr->link;
}
}
delete p;
delete curr;
}
The code for deleteSmallest is as follows:
template <class Type>
void UnorderedLinkedList<Type>::deleteSmallest()
{
NodeType<Type>* curr;
NodeType<Type>* p;
NodeType<Type>* q;
NodeType<Type>* r;
curr = first;
if (first == NULL)
throw std::runtime_error("Cannot delete from an empty list");
else
{
for(int i = 0; i < count; i++)
{
if(curr->link->info < curr->info)
{
int smallest = curr->link->info;
p = curr;
q = curr->link;
}
curr = curr->link;
}
}
r = q->link;
p->link = q->link;
delete q;
}
The error that I get is:
1 [main] Project 5 4044 cygwin_exception::open_stackdumpfile: Dumping stack trace to Project 5.exe.stackdump
Sorry to post a large question, but can someone explain what the error means in this situation and what I'm doing that is causing this to come up? Thank you!
For deleteAll() you should be doing something like this:
else
{
for (Node* prev = curr; curr != NULL; prev = curr, curr = curr->link)
{
if (curr->info == deleteItem)
{
NodeType<Type>* temp = curr;
curr = curr->link;
if (prev)
prev->next = curr;
delete temp;
}
}
}
The way you had it before was not deleting curr at all. You should also remove the delete p and delete curr at the bottom as they are redundant.
And for deleteSmallest(), you need to keep a pointer pointing to the smallest node (and a previous node pointing to the one before it) so when the loop finishes you know what delete:
else
{
Node* prev = NULL, **smallest;
for (Node** curr = smallest = head, *back(*head); *curr != NULL; back = *curr, curr = &(*curr)->link)
{
if ((*curr)->info < (*smallest)->info)
{
prev = back;
smallest = curr;
}
}
Node* temp = *smallest;
*smallest = (*smallest)->link;
if (prev)
prev->link = *smallest;
delete temp;
}
I have create a clear () function, which when is called, clears the entire Hash Table and resets the size to 0. The function is causing memory leaks in my program but I do not see a possible leak..
Here is my clear() function:
void HashMap::clear()
{
unsigned int capacity = HashMap::bucketCount();
for (unsigned int i = 0; i < capacity; i++)
{
Node* temp;
Node* StoreThenDel = new Node;
if (HashTable[i] != nullptr)
{
temp = HashTable[i];
HashTable[i] = nullptr;
while(temp->next != nullptr)
{
StoreThenDel = temp;
if(StoreThenDel->next != nullptr)
temp = StoreThenDel->next;
delete StoreThenDel;
}
}
}
sz=0; // reset size
}
You do a StoreThenDel = new Node. This allocates memory for a Node on the heap. Afterwards you do a StoreThenDel = temp, losing the information about where you allocated memory for the Node on the heap.
Your while loop and temp variables are just very confusing, try to simplify the code to something like the below and you will find that the simpler code has fewer problems.
for (unsigned int i = 0; i < capacity; ++i)
{
while (HashTable[i] != nullptr)
{
Node* temp = HashTable[i];
HashTable[i] = temp->next;
delete temp;
}
}
Node* StoreThenDel = new Node;
This new is a leak and is unnecessary.
while(temp->next != nullptr)
This loop condition stops too soon. It should run until temp != nullptr. As is it leaks the last entry in each list.
if(StoreThenDel->next != nullptr)
temp = StoreThenDel->next;
That assignment of temp should not be conditional.