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.
Related
I am making an array with a linked list in it and I am trying to get rid of memory leaks and uninitialised values. Valgrind reports
" Conditional jump or move depends on uninitialised value(s) "
Does anyone know why this is?
Here is my code:
#include<iostream>
#include<string>
using namespace std;
struct Item
{
int key;
string value;
Item *next;
};
//array for storing items and lists of items
//- allocate array
//- create a linked list at array index if needed
Item **items = new Item*[3];
void add_item(int key, string value, int index)
{
//create new item
Item *it = new Item;
it->key = key;
it->value = value;
it->next = NULL;
//if there are no items at location
if(items[index] == NULL)
items[index] = it;
//if there is, iterate through linked list and add item at end
else
{
Item* curr = items[index]; //start of linked list
while(curr->next != NULL)
curr = curr->next;
curr->next = it;
}
}
int main()
{
Item *curr;
add_item(1, "Happy", 0);
add_item(2, "Sad", 0);
add_item(3, "Laughing", 1);
add_item(4, "Angry", 2);
for(int i=0; i<3; i++)
{
curr = items[i];
while(curr != NULL)
{
cout<<curr->key<<" "<<curr->value;
curr = curr->next;
if(curr != NULL)
cout<<" --> ";
else
cout<<endl;
}
}
//delete memory
for(int i=0; i<3; i++)
{
curr = items[i]; //start of list
//delete linked list starting at array index
while(curr != NULL)
{
Item *temp = curr;
curr = curr->next;
delete temp;
}
}
delete [] items; //delete array
return 0;
}
I have rewritten the program several times and I honestly have no idea why it says that.
Item **items = new Item*[3]; creates an array of 3 uninitialized pointers. So, the check if(items[index] == NULL) might not be true in the first call. The random value will make the program crash at while(curr->next != NULL).
You can fix it by initializing the pointer: Item **items = new Item*[3]();. The () in the end default initializes the values (e.g., to nullptr in this case).
After that the address sanitizer does not complain anymore: https://godbolt.org/z/3xxzYa4Gs
I have a HashTable, where collisions are handled by chaining (linked lists). The first node of every linked list has a pointer from each array position. Shown below is a regular constructor along with rule of 3 functions.
Although my code is compiling and my functions (add, remove, etc) are producing the right output, I am having an issue with the destructor (the IDE points to it with a Thread 1: signal SIGABRT) and the console displays "pointer being freed was not allocated" after my driver program finishes running. I can't figure out what went wrong so any help would be appreciated. I did not include my code for any of the other functions (add, remove, etc) aside from constructors/destructors.
Even when I comment out the copy and overloaded= constructors, the same issue still arise with the destructor.
specification:
class HashTable {
public:
HashTable(int);
~HashTable();
HashTable(const HashTable &);
HashTable& operator=(const HashTable &);
private:
struct Node {
string word;
int wordCount;
Node * next;
// node constructor
Node(string w, int count) {
word = w;
wordCount = count;
next = nullptr;
}
};
Node** wordList;
int capacity;
int hashFunction(string);
};
Implementation of big 4:
constructor:
HashTable::HashTable(int cap) {
capacity = cap;
wordList = new Node*[capacity];
for (int i = 0; i < capacity; i++)
wordList[i] = nullptr;
}
destructor (where the problem seems to be)
HashTable::~HashTable() {
for (int i = 0; i < capacity; i++) {
Node* curr = wordList[i];
while (curr != nullptr) {
Node* prev = curr;
curr = curr->next;
delete prev;
}
}
delete[] wordList;
}
copy constructor:
HashTable::HashTable(const HashTable &obj) {
capacity = obj.capacity;
wordList = new Node*[capacity];
for (int i = 0; i < capacity; i++) {
if (obj.wordList[i] == nullptr)
continue;
Node * newNode = new Node(obj.wordList[i]->word,
obj.wordList[i]->wordCount);
wordList[i] = newNode;
}
}
copy assignment operator:
HashTable& HashTable::operator=(const HashTable &obj) {
if (this != &obj) {
for (int i = 0; i < capacity; i++) {
Node* curr = wordList[i];
while (curr != nullptr) {
Node* prev = curr;
curr = curr->next;
delete prev;
}
}
delete[] this->wordList;
this->capacity = obj.capacity;
this->wordList = new Node*[capacity];
for (int i = 0; i < this->capacity; i++) {
if (obj.wordList[i] == nullptr)
continue;
Node * newNode = new Node(obj.wordList[i]->word,
obj.wordList[i]->wordCount);
this->wordList[i] = newNode;
}
}
return *this;
}
In your copy constructor and copy assignment operator, you are copying the list pointers from obj into this. This leaves the same pointers in both objects, resulting in double free and other issues once one HashTable has been freed,
When you do the copies, you need to do a Deep Copy, which is to allocate new nodes for the copy of the word list.
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);
}
}
}
I'm trying to delete the n'th element, which is a random number from 1 to n.
My code does this fine (correct element is deleted and surrounding elemnts are connected) but when it comes to being efficient, it is crashing when I un-comment the line delete (nodeToRemove); and I'm not sure why. Does anyone have any insight?
Assuming my struct looks like :
struct Node {
int data; // The data being stored at the node
Node *next; // Pointer to the next node
};
//------------------------------------------------------------------------------
void deleteNthElement (Node * & head, Node * &temp, int random)
{
temp = head;
Node *nodeToRemove;
if (random == 1)
{
nodeToRemove = temp;
head = head->next;
}
else
{
for (int i = 1; i < random - 1; i++)
temp = temp->next;
nodeToRemove = temp->next;
temp->next = temp->next->next;
}
// delete (nodeToRemove); <----- uncommenting this leads to crash,
}//end deleteNthElement()
//------------------------------------------
int main()
{
Node *head = NULL;
Node *temp;
Node *listarray[n[i]];
int n[] = {1000, 5000, 9000, 105000, 400000, 500000, 505000, 800000, 995000, 1000000};
for (int j = 0; j < n[i]; j++)
listarray[j] = new (Node);
//start timer
begin = clock();
//fill it
for (int j = 0; j < n[i]; j++)
{
listarray[j]->data = (rand() % n[i] + 1);
insertNodeInOrder (head, temp, listarray[j]);
}
//delete it
for (int j = 0; j < n[i]; j++)
deleteNthElement (head, temp, (rand() % (n[i] - j) + 1));
//deallocate
for (int j = 0; j < n[i]; j++)
delete listarray[j];
delete *listarray;
//end timer
}
You're picking the wrong Node, you want:
...
nodeToRemove = temp;
...
At least, you have to check for the end of the list, that is, you need to avoid access to null pointers (i really hope you set next to 0 at the end of the list). If you add the allocation parts, I will extend my answer.
void deleteNthElement (Node * & head, Node * &temp, int random)
{
temp = head;
Node *nodeToRemove;
if (random == 1)
{
nodeToRemove = temp;
if(head != 0)
head = head->next;
} else {
for (int i = 1; i < random - 1; i++)
if(temp != 0)
temp = temp->next;
else throw 1; // no such index; throw something more verbose :)
if(temp == 0)
throw 1; // same situation as above
nodeToRemove = temp->next;
if(nodeToRemove == 0)
throw 1; // same situation as above
temp->next = temp->next->next;
}
if(nodeToRemove == 0)
throw 1; //no such index; ... as the above 3
delete nodeToRemove;
}//end deleteNthElement()
Some clean-up first:
Why pass in two pointers here? do you need the value of temp out? If so why not return it?
Also why the node * & temp? (I can see why it is done for head).
int random should probably be called something like index as it describes the functionality better (as far as the function is concerned, there is nothing random about it).
The same with temp.
I propose:
void delete_element (Node* &head, int index)
{
Node* parent_node = head;
Node* node_to_remove;
//...
We don't need temp if we are removing the head. Also, we generally 0 index things, so we should reflect that too. Thus it becomes:
if (index== 0)
{
node_to_remove= head;
head = head->next;
}
Now we get to the main bit. The loop is just there to step through to the parent node of the node to delete, so we can simplify it a little and add checks to make sure we can't 'fall off' the end of the list.
We then have to make sure there is a node to remove, (so another check). We don't need to check for a node beyond as assigning nullptr isn't a problem (I am assuming that an invalid pointer is set to nullptr here):
{
while(--index && parent_node->next){ //pre-decrement means we stop before the one we want (parent)
parent_node = parent_node->next;}
if (parent_node->next){node_to_remove= parent_node->next;}
else {return;} //no point deleting it if it doesnt exist
parent_node->next = node_to_remove->next;//less indirection is always good. Ok if this is nullptr
}
Incidentally, this fixes a probable off by one error. Which is probably your problem (did it crash every time? only when deleting the last element? next to last?
Now we just need to delete it.
Putting it all together:
void delete_element (Node* &head, int index)
{
Node* parent_node = head;
Node* node_to_remove;
if (index== 0)
{
node_to_remove= head;
head = head->next;
}
else
{
while(--index && parent_node->next){ //pre-decrement means we stop before the one we want (parent)
parent_node = parent_node->next;}
if (parent_node->next){node_to_remove= parent_node->next;}
else {return;} //no point deleting it if it doesnt exist
parent_node->next = node_to_remove->next;//less indirection is always good. Ok if this is nullptr
}
delete node_to_remove;
return;
}
And that should work fine. The checks will prevent us dereferencing null pointers which was (probably) what caused you to crash. Can't tell without full code.
So I've got this insert function for a doubly linked list that is working for the most part just up until I try to insert a new node at a given index. I'm having trouble with linking it correctly to the nodes before and after it, if anyone could see why, I keep getting errors when I try to assign one of the points I'll point out in the code:
void insert(int index, ItemType& item)
{
int pos = 0;
Node* current = new Node;
Node* n = new Node;
n->info = item;
if (index >= 0 && index <= size)
{
if (size == 0)
{
head = n;
tail = n;
n->next = NULL;
n->prev = NULL;
size++;
return;
}
else if (index == 0)
{
n->prev = NULL;
n->next = head;
head->prev = n;
head = n;
size++;
return;
}
else if (index == size)
{
n->next = NULL;
n->prev = tail;
tail->next = n;
tail = n;
size++;
return;
}
else if (index < size/2)
{
current = head;
while(pos != index)
{
current = current->next;
pos++;
}
}
else if (index > size/2)
{
int endpos = size - 1;
current = tail;
while(endpos != index)
{
current = current->prev;
endpos--;
}
}
n->next = current;
current->prev->next = n; // HERE is where the code breaks, don't know why.
n->prev = current->prev;
current->prev = n;
size++;
}
}
So the code breaks at the current->prev->next = n statement stating there is an access violation writing location. So I'm not sure if that is coded right or if I've messed up in pointing assignments in earlier code. If anyone knows why its doing that and can point me in the right direction that would be awesome. Thanks.
From my observation,
Your code fails when index = size/2.
When there are two elements(size == 2) and when you try to insert at position 1, then current->prev->next = n; is meaningless
Do one of these changes else if (index <= size/2) or else if (index >= size/2)
If current is the first node in the list, then current->prev will be NULL, so current->prev->next will cause problems. You should check if current is the first item in the list before this line.
Also, your code leaks memory because you are allocating a new Node for current and you do not delete it. Since you are using current to move through the list rather than to create a new node, you should declare it as just
Node* current;
rather than
Node* current = new Node;