C++ Binary Tree Implementation - Deleting Pointer Causes - c++

I am working on a pretty basic binary tree implementation in C++, but I am currently having a problem that deleting a pointer to the root node crashes the program. In Dev-C++ debug mode the error returned is: "Program received signal SIGTRAP, Trace/breakpoint trap", but when I check with "info breakpoints", it says there are no breakpoints or watchpoints. I'm pretty confused about this and have been spending a lot of time checking if I have used and declared all the pointers correctly, any help would greatly be appreciated!
#include <iostream>
#include <vector>
using namespace std;
class Node {
public:
int key;
Node * left_child = NULL;
Node * right_child = NULL;
};
class Tree {
public:
int num_nodes;
vector<Node> nodes;
int read() {
cin >> num_nodes;
nodes.resize(num_nodes);
int input_key, input_left, input_right, root_node = 0;
for (int i = 0; i < num_nodes; i++) {
cin >> input_key >> input_left >> input_right;
if(input_key >= nodes.size()) {
nodes.resize(input_key+1);
}
if(i==0) {
root_node = input_key;
}
nodes[input_key].key = input_key;
if(input_left >= 0) {
nodes[input_key].left_child = &nodes[input_left];
}
if(input_right >= 0) {
nodes[input_key].right_child = &nodes[input_right];
}
}
return root_node;
}
};
int main() {
Tree t;
int root_index = 0;
root_index = t.read();
Node * root_ptr = new Node;
root_ptr = &(t.nodes[root_index]);
delete root_ptr; //when I take this line out, it works
}
Sample Input (no output expected):
3
4 2 5
2 -1 -1
2 -1 -1

Firstly, this line is useless:
Node * root_ptr = new Node;
You immediately reassign root_ptr to something else. So the line does nothing but allocate memory. You then assign root_ptr as follows:
&(t.nodes[root_index]);
The variable t you declared on the stack. You end up getting a pointer to a vector element, an element you never allocated yourself. If you did not allocate it yourself, you cannot delete it. Any allocation by the vector will be handled by the vector, and the vector itself is a stack-allocated, so you cannot delete it.
That is why the delete line crashes.
Additionally, you say it is a simple binary tree implementation, but it is not. You have a vector in there, and you have a strange way of assigning the tree elements, so you've created some kind of hybrid data structure.

Related

Segmentation Fault 11 whenever I run this. Would like assistance/feedback

So I'm making a really rudimentary implementation of a circular list. I haven't made the remove function yet. Whenever I run the cpp, I get a seg fault 11. Any feedback would be much appreciated. Thank you.
#include <iostream>
using namespace std;
struct node{
node* next=NULL;
bool tail= false;
int contents;
};
node* start;//start is a pointer that exists at the start of the list before the first element
class CircList{
node *seek;
public:
CircList (){ //creates a list of one node that points to itself
node *b= new node;
b->contents=0;
b->next = b;
start->next=b;
b->tail=true;
}
bool empty(){
if(start->next==NULL){
return true;
}
return false;
}
int size(CircList a){
if(start->next==NULL){
cout<<"size is 0 \n";
return true;
}
seek=start->next;
for(int i=0; i++;){
if(seek->tail==true){
cout<<"size is "<<i;
}
seek=seek->next;
}
return 0;
}
void insert(int pos, int val){
if(start->next ==NULL){//if inseting when the list is empty
node *b= new node;
b->next = b;
b->tail=true;
return;
}
node *b= new node;
b->contents= val;
seek=start->next;
for(int i=0;i<=pos; i++){
if(seek->tail==true){//if inserting at the end
seek->tail=false;
b->tail=true;
seek->next=b;
b->next=start->next;
}
if(pos==i){//if inserting between two nodes
b->next = seek->next;
seek->next = b;
}
seek=seek->next;
}
}
void remove(int a){
seek=start->next;
for(int i=0;i<=a-1; i++){
if(i<a){
seek=seek->next;
}
if(i==a-1){
}
}
}
void display(){
cout<<start->next->contents; //will also be completed in the near future
seek=start->next;
for(int i=0; ;i++){
if(seek->tail==false){
cout<<seek->contents<<"\n";
}
if(seek->tail==true){
cout<<seek->contents<<"\n";
return;
}
}
}
};
That was the .h file. The following is the cpp. I just plugged in numbers to test. I want to get the program running so that I can test how it behaves.
#include <iostream>
#include "CircList.h"
using namespace std;
int main(){
CircList a;
a.insert (5,5);
a.insert (5,5);
a.insert (1,4);
a.insert (20,65);
a.insert (3,7);
a.size(a);
a.display();
}
I kept treating start as a node instead of a pointer. By making start = Null and replacing all the "start->next"'s with "start", I got it to compile and run. But now it's only infinitely inserting nodes with a value of 0 in the contents.
Edit: I fixed it. By changing that weird for loop in the display function to a while loop, it doesn't do infinite inserts of the node in the constructor, anymore. It seems to work decently enough now.
This here causes a seg fault
start->next=b;
because start is NULL at the start of the program so you are de-referencing a null pointer.
instead set start to the first node in your constructor
start = b;
Your global variable start is an uninitialized pointer, yet you dereference it all over the place.

Can anyone please tell me why is it showing "runtime error"?

I'm trying to implement hash table, but I'm getting a runtime error in the for loop of createHashTable() function. Can anyone please tell me why is it showing this "runtime error"? Is it StackOverflow error?
#include <iostream>
using namespace std;
#define LOAD_FACTOR 20
struct ListNode{
int data;
struct ListNode *next;
};
struct HashTableNode{
int bCount; // number of elements in the block
struct ListNode *next;
};
struct HashTable{
int tSize; // table size
int count; // total number of elements in the table
struct HashTableNode **hashTableNodeArray;
};
int hashFunction(struct HashTable *h, int data){
return data % h->tSize;
}
struct HashTable * createHashTable(int numberOfElements){
struct HashTable *h = new HashTable;
h->count = 0;
h->tSize = numberOfElements / LOAD_FACTOR;
h->hashTableNodeArray = new HashTableNode *[h->tSize];
for(int i = 0; i < h->tSize; ++i){
// this is where it is showing runtime error
h->hashTableNodeArray[i]->bCount = 0;
h->hashTableNodeArray[i]->next = nullptr;
}
return h;
}
void deleteHashTable(struct HashTable *h){
struct ListNode *node, *tmp;
for(int i = 0; i < h->tSize; ++i){
node = h->hashTableNodeArray[i]->next;
while(node != nullptr){
tmp = node;
node = node->next;
delete tmp;
}
}
delete[] h->hashTableNodeArray;
delete h;
}
int main(int argc, char **argv){
struct HashTable *h = createHashTable(220);
deleteHashTable(h);
return 0;
}
h->hashTableNodeArray = new HashTableNode *[h->tSize];
This allocates an array of pointers, but not the actual hashtablenodes. In the following loop you try to write to them which is undefined behaviour.
You are missing in your loop:
h->hashTableNodeArray[i] = new HashTableNode;
The problem is here:
h->hashTableNodeArray = new HashTableNode *[h->tSize];
for(int i = 0; i < h->tSize; ++i){
// this is where it is showing runtime error
h->hashTableNodeArray[i]->bCount = 0;
h->hashTableNodeArray[i]->next = nullptr;
}
You allocate an array of pointers, but don't actually make the pointers point anywhere valid which means their values are indeterminate (and in reality seemingly random). You then proceed to dereference these uninitialized pointers, and write to memory using the pointers, without knowing where in memory you will write.
This leads to undefined behavior, and most likely your crash.
The solution? Either don't use pointers, or explicitly allocate the memory for the pointers. My recommendation is to stop using pointers altogether, create proper copy- and move-constructors, and use std::vector instead.

Frustrating pointer error

For the life of me, I can't figure out what is going wrong. I know the error is occurring in the function marked displayQueue below, but all the syntax and logic seems correct.
Visual studio is giving me the error: "Unhandled exception at 0x00215A86 in ex11_1.exe: 0xC0000005: Access violation reading location 0xCDCDCDE1." But really, I have no idea what this is referring to...
#include <iostream>
#include <cstdlib>
#include <string>
using namespace std;
struct QueueNode {
string data;
QueueNode *link;
};
typedef QueueNode* QueueNodePtr;
class Queue {
public:
// Constructors/Destructor.
Queue();
Queue(const Queue& aQueue);
// Accessors.
bool empty() const;
void displayQueue ();
// Mutators.
void add(string item);
string remove(); // This should probably be replaced with pop and top - especially for displayQueue... empty() in functions can be replaced with count == 0. Yes, I will do this.
private:
QueueNodePtr front; // Points to head of linked-list queue.
QueueNodePtr back; // Points to tail of linked-list queue.
size_t count;
};
int main () {
Queue myQueue;
myQueue.add("abc");
myQueue.add("def");
myQueue.add("ghi");
myQueue.displayQueue(); // The error is here somewhere. abc is printed and but nothing else.
system("pause");
return 0;
}
Queue::Queue() {
front = NULL;
back = NULL;
count = 0;
}
Queue::Queue(const Queue& aQueue) {
front = aQueue.front;
back = aQueue.back;
count = aQueue.count;
}
bool Queue::empty() const {
if (count == 0) {
return 1;
} else {
return 0;
}
}
void Queue::displayQueue () {
// There is a problem here somewhere...
QueueNodePtr here = front;
for (int i = 0; i < count; i++) {
cout << here->data << endl;
here = here->link;
}
}
void Queue::add(string item) {
QueueNodePtr newNode;
newNode = new QueueNode;
if (count == 0) {
// If inserted in an empty queue, back and front point to same element.
newNode->data = item;
// newNode->link = NULL; // Not sure this part is even necessary.
back = newNode;
front = back;
} else {
// Otherwise, leave front pointer where it's at.
newNode->data = item;
newNode->link = back->link;
back = newNode;
}
count ++;
}
string Queue::remove() {
string returnString;
if (count == 0) {
return returnString;
} else if (count == 1) {
returnString = front->data;
front = NULL;
back = front;
count--;
return returnString;
} else {
returnString = front->data;
front = front->link;
count--;
return returnString;
}
}
EDIT: If anyone can give me any tips on using the debugger to solve problems like this, or give me a link that might explain this it would be greatly appreciated.
The error is on this line, but for the sake of learning, I won't give the correct version, just a few hints:
newNode->link = back->link;
At the point where this code is being executed, which node does back point to? What does its link point to? Whose node's link do you need to modify?
As for finding this yourself, you could have used the debugger to figure out which line causes the crash; this would have indicated that something is wrong with a link value.
P.S. Your copy constructor doesn't actually copy the linked list; it just creates a new Queue object that points to the same linked list, so if you add an element to the copy, it will show up in the original Queue.
An access violation at address 0xCDCDCDCD means that your program loaded a pointer from uninitialized storage and then dereferenced it. Microsoft's debugging allocator uses this pattern for newly allocated uninitialized storage, and in a suitable compilation mode, also for stack locations. If you treat such uninitialized storage as a pointer variable, the pattern is recognizeable in that pointer. Moreover, it is almost certainly an invalid pointer that will trigger an exception. So the benefit is that the use of the invalid pointer is caught quickly, and the pattern tells you that the cause is quite likely uninitialized storage (though this is not 100% conclusive).
For example:
struct contains_pointer { char *str; } *ptr = malloc(sizeof *ptr);
strcpy(ptr->str, "abc"); // ptr->str is uninitialized
Or:
int *pint;
*pint = 0; // pint is uninitialized
To have the compiler and library overwrite uninitialized storage with a pattern like CDCDCD... can be quite helpful. You should pinpoint the location of the crash with the debugger, and then work backward from there: where did the pointer value originate and why wasn't it initialized.
(A bad pointer to the address CDCDCDCD could result in other ways: sheer fluke (unlikely) or a use-after-free bug: the program frees some memory but continues to keep a pointer to it, without using it for a while. The memory is then re-allocated to some other part of the program, and marked uninitialized, and by chance, the original user of the pointer makes a use of it, loading a pointer value from the memory. At that moment, a CDCDCDCD pointer results, so it looks like a use-before-init bug, when in fact it's a use-after-free bug. Debugging based on "memory poisoning" patterns is not accurate!)

Code for Huffman tree using std::unique_ptr not working

I'm working on building a Huffman encoder for a homework assignment, and I need to know why my code isn't working. I've asked elsewhere on an earlier version, and got a tip to use std::unique_ptr so that the nodes referenced by my pointers won't be deleted from memory when they're deleted from the vector.
This is what I have so far:
#include <iostream> // Allows the use of std::cout >> and std::cin <<.
#include <string> // Allows the use of getline().
#include <fstream> // Allows the use of file I/O.
#include <utility> // Allows the use of std::bitset.
#include <vector> // Allows the use of vectors.
#include <algorithm> // Allows the use of std::sort().
#include <memory> // Allows the use of std::unique_ptr.
struct node
{
char data;
int frequency;
std::bitset<1> code;
node *left;
node *right;
bool operator<(const node &temp) const {return frequency < temp.frequency;}
};
std::vector<node> nodeVector;
void getHuffmanData()
{
std::ifstream inStream;
int size;
int tempFrequency;
char tempData;
node tempNode;
inStream.open("huff-source.txt");
if (inStream.fail())
{
std::cout << "Failure opening input file.\n";
exit(1);
}
inStream >> size;
while (inStream.peek() != EOF)
{
inStream >> tempData;
inStream >> tempFrequency;
tempNode.data = tempData;
tempNode.frequency = tempFrequency;
nodeVector.push_back(tempNode);
}
inStream.close();
}
node buildHuffmanTree() // Returns the root node, which points to all other nodes.
{
node tempNode;
node *x, *y;
std::unique_ptr<node> a (new node);
std::unique_ptr<node> b (new node);
while (!nodeVector.empty())
{
std::sort(nodeVector.begin(), nodeVector.end());
*a = nodeVector.front();
x = a.release();
tempNode.left = x;
nodeVector.erase(nodeVector.begin());
*b = nodeVector.front();
y = b.release();
tempNode.right = y;
nodeVector.erase(nodeVector.begin());
tempNode.frequency = x->frequency + y->frequency;
nodeVector.push_back(tempNode);
std::sort(nodeVector.begin(), nodeVector.end());
if (nodeVector.size() == 1) {break;}
}
return tempNode;
}
int main()
{
node test;
getHuffmanData();
test = buildHuffmanTree();
std::cout << "Press 'Enter' to continue...";
std::cin.get();
return 0;
}
My sample input file, is as follows:
4
a 119
b 20
c 44
d 127
Now, the error message I'm getting in Xcode occurs after it runs once through buildHuffmanTree(). It says 'Thread 1: EXC_BAD_ACCESS (code=1, address=0x0)' at the line containing '*a = nodeVector.front();'. How would I go about correcting the loop so that the function can return a proper tree, illustrated like this:
310
/ \
127 183
d / \
64 119
/ \ a
20 44
b c
You are trying to write to a dereferenced null pointer.
Let me step through your code to show you the error.
node buildHuffmanTree() // Returns the root node, which points to all other nodes.
{
node tempNode;
node *x, *y;
std::unique_ptr<node> a (new node); // a now points to a node in the heap
std::unique_ptr<node> b (new node); // b now points to a node in the heap
while (!nodeVector.empty())
{
std::sort(nodeVector.begin(), nodeVector.end());
*a = nodeVector.front(); // you copy the first node in the vector into the node
// on the heap pointed to by a
x = a.release(); // x now points to the node on the heap pointed to by a
// a now holds a nullptr and will not delete the node on the heap
tempNode.left = x; // tempNode.left now points to the node on the heap
nodeVector.erase(nodeVector.begin());
. . .
tempNode.frequency = x->frequency + y->frequency;
nodeVector.push_back(tempNode);
std::sort(nodeVector.begin(), nodeVector.end());
if (nodeVector.size() == 1) {break;}
}
return tempNode;
}
Now we go through the while loop again
while (!nodeVector.empty())
{
std::sort(nodeVector.begin(), nodeVector.end());
*a = nodeVector.front(); // a now holds a nullptr, so this is BAD
. . .
}
I believe you do not fully understand the use of std::unique_ptr.
You probably want a collection of std::unique_ptrs to all your node objects
to persist throughout your program so you have a unique set of nodes that will not disappear.
To link these nodes into your tree, use regular pointers (or maybe shared).
Unique pointers should be used when the object/code block containing the pointer
has sole responsibility to delete the allocated memory pointed to by the pointer.

Returning Objects in C++ (Binary Tree)

Disclaimer: This is for an assignment. I would like pointers in the right direction (no pun intended) rather than straight code solutions.
I'm attempting to implement a max winner tree (a binary tree in which the node's value is the max of it's children's values, so that the root eventually has the max value of all the bottom leaves). My current MaxWinnerTree initializes a tree full of -1s, just as place holders for values to be inserted later on.
MaxWinnerTree.cpp
#include "MaxWinnerTree.h"
MaxWinnerTree::MaxWinnerTree(int elements)
{
int size = 1;
while (size<elements)
size = size * 2; //gets closest power of 2 to create full bottom row
*a = new Node[size];
for (int i = (2*elements-1); i>0; i--)
{
if (i > elements-1) //leaf
{
//Create new nodes with data -1, store pointer to it in array
*a[i] = (newNode(i,-1,NULL,NULL,NULL));
}
else // not leaf
{
//Create node with data = max of children, store pointer
*a[i] = newNode(i,-1,a[i*2],a[i*2 +1], NULL); //create
a[i]->data = max(a[i*2]->data, a[i*2+1]->data); //gets max
a[i]->right->parent = a[i];
a[i]->left->parent = a[i];
}
}
}
Node MaxWinnerTree::newNode(int key, int data, Node *left, Node *right, Node *parent)
{
Node *n = new Node;
key = key;
data = data;
left = left;
right = right;
parent = parent;
return *n;
}
In my Main, I attempt to create a MaxWinnerTree object to perform actions on (insertion, etc), but I know the way I'm doing it is incorrect. My MaxWinnerTree method doesn't return a value, and the only objects I'm creating are an array and then a linked mess of nodes. As I type this, I'm going to go back and attempt to return a linked list as my tree and go from there, but is this the direction that I should be going in?
Main.cpp
int main (){
bool quit;
int command, elements, binSize;
cout<<"Welcome to assignment 6!"<<endl;
while (!quit)
{
cout<<"Choose an option for the test: 1-> First fit, 2-> Best Fit, 3-> Quit"<<endl;
cin>>command;
if(command==1)
{
cout<<"First Fit!";
cout<<"Enter number of objects: ";
cin>> elements;
cout<<"\n Enter capacities of bins: ";
cin>> binSize;
cout<<"\n";
MaxWinnerTree* tree = new MaxWinnerTree(elements); //Throws x86 error, also throws error when not decared as a pointer
tree->insert(7);
//Irrelevant rest of non-applicable code
In essence, what do I need to do differently to get a tree object that I can operate on after calling my constructor?
Also: I'm shaky on pointers, so if something looks off or bad practice, please let me know.