Read access violation in tree structure - c++

I'm working on this assignment and I can't seem to stop this read access violation error. I am new to C++ and I think part of my issue is using pointers when they aren't necessary (I think), but I've also looked at this code and traced through it so many times with the debugger that I think I'm missing something obvious.
The assignment is to implement a Huffman encoder. To do this I have to create a HuffmanTree class and a HuffmanProcedure class, and I am provided with a (mostly) complete Heap class (minheap).
The HuffmanProcedure class has to use the Heap class to store and create HuffmanTrees until I have a Huffman code for every single lowercase letter.
When running the code, I get a read access violation error in the helper I wrote for my Tree destructor, treeRemovalHelper.
The specific error I get (using Visual Studio 2019 targeting C++11):
Exception thrown: read access violation. root was 0xDDDDDDDD
Here's where the error is occurring:
// Destructor
HuffmanTree::~HuffmanTree() {
if (rootPtr != nullptr) {
rootPtr = treeRemovalHelper(rootPtr);
} else {
delete rootPtr;
}
}
// Helper
HuffmanTree::Node* HuffmanTree::treeRemovalHelper(Node* root)
{
if (root == nullptr) {
return nullptr;
}
else {
treeRemovalHelper(root->rightChild); // THIS IS WHERE I GET THE ERROR
treeRemovalHelper(root->leftChild);
delete root;
}
return nullptr;
}
Can you help point me in the right direction here?
I am happy to provide my full code, just in case it helps. I want to note that all of the code is mine, with the exception of some of the methods in the Heap class (which the instructor provided, and I have noted in the code).
Here are the three constructors for the HuffmanTree class:
HuffmanTree::HuffmanTree() : rootPtr(nullptr) {}
HuffmanTree::HuffmanTree(const char letter, const int weight) {
rootPtr = new Node{
letter,
weight,
nullptr,
nullptr
};
}
HuffmanTree::HuffmanTree(HuffmanTree* smallestTree, HuffmanTree* secondSmallestTree)
{
int mergedWeight = smallestTree->rootPtr->weight + secondSmallestTree->rootPtr->weight;
char tempChar;
if (smallestTree->rootPtr->letter < secondSmallestTree->rootPtr->letter) {
tempChar = smallestTree->rootPtr->letter;
} else {
tempChar = secondSmallestTree->rootPtr->letter;
}
rootPtr = new Node{
tempChar,
mergedWeight,
smallestTree->rootPtr,
secondSmallestTree->rootPtr
};
}

I found your problem:
After you delete the root, remember to set it to nullptr.
// Helper
HuffmanTree::Node* HuffmanTree::treeRemovalHelper(Node* root)
{
if (root == nullptr) {
return nullptr;
}
else {
treeRemovalHelper(root->rightChild); // THIS IS WHERE I GET THE ERROR
treeRemovalHelper(root->leftChild);
delete root;
root = nullptr; -->> FIX
}
return nullptr;
}

Related

what's wrong here ? while (temp->ptr_Next != NULL) fails, if (temp->ptr_Next == NULL) works

I've been making a doubly linked list and the while statements are going a bit wonky. I'm sure there's a simple explanation, but I'm not seeing it. Can anyone help?
This is working (Embarcadero RAD studio 11.1 - C++ Builder - Classic compiler (not Clang))
TDoubleLinkedNode* __fastcall TDoubleLinkedList::CreateNode ( int ID
, UnicodeString Name
)
{
// use "malloc" (or "new") to create the node in the heap
// it won't be deleted automatically when the function goes out of scope
// return the pointer to the structure
// let the calling function set PriorNode & NextNode
struct TDoubleLinkedNode* ReturnNode = (struct TDoubleLinkedNode*)malloc(sizeof(struct TDoubleLinkedNode));
ReturnNode->ID = ID;
ReturnNode->Name = Name;
ReturnNode->ptr_PriorNode = NULL;
ReturnNode->ptr_NextNode = NULL;
return ReturnNode;
}
void __fastcall TDoubleLinkedList::Add_ToEnd ( int ID
, UnicodeString Name
)
{
struct TDoubleLinkedNode* newNode = CreateNode(ID,Name);
if(this->IsEmpty)
{
// Head Pointer has not been initialised. Set as newNode
this->FHeadNode = newNode;
// This is the first Record.
newNode->ptr_PriorNode = NULL;
newNode->ptr_NextNode = NULL;
return;
}
else
{
struct TDoubleLinkedNode* oldHeadNode = this->FHeadNode;
struct TDoubleLinkedNode* tempNode = this->FHeadNode;
do // keep iterating until a break statement is triggered
{
if (tempNode->ptr_NextNode == NULL) // terminate the do while statement
{
break;
}
tempNode = tempNode->ptr_NextNode; // Move to the "Next" record
}
while (true); // always repeat...
tempNode->ptr_NextNode = newNode;
newNode->ptr_PriorNode = tempNode;
newNode->ptr_NextNode = NULL;
}
}
However, if I replace
do
{
if (tempNode->ptr_NextNode == NULL)break;
}
while (true);
with
while (tempNode->ptr_NextNode != NULL)
{
tempNode = tempNode->ptr_NextNode ;
}
the while statement does not break when tempNode->ptr_NextNode == NULL resulting in tempNode being set to NULL making the tempNode->ptr_NextNode = newNode that follows fail (Since you can't assign data to a non existent object).
I have been stepping through and the while is definitely running when tempNode->ptr_NextNode == NULL , when my understanding is it shouldn't??
I'm sure this isn't the only area that's messed up (there's quite a few while statements).
I'm adding 6 test records and only able to retrieve 5! so it's obvious something is up. If you can shed some light on what I'm not understanding I'd be grateful
thanks, J
I haven't used CBuilder for some 20 years, but if what you say is exactly what happens, if replacing that 'do while' loop to that 'while' changes the behavior, and you can clearly see that crazy thing occurring when you are stepping through it, it also seems illogical to me.
I don't know how it is now, but there in the beginning of the century, since C++ Builder has a lot of complicated links with Object Pascal libraries, it was not so uncommon to reach very strange situations, with crazy things happening in debug. What used to help was to do a "rebuild all", possibly removing all temporary files I could find in the project.
Maybe it helps.
And I also support our colleagues' comments regarding updating your code to use more appropriate C++ alternatives, much simpler and efficient ones, if possible (I know sometimes you can be working on legacy software which may not be easy to update).
And it is actually also very likely you are seen undefined behavior due to corrupted content, as people also said in comments. That only you can determine.
Update: I've just seen the other answer here just posted by Remy Lebeau, and I would like to add he is right regarding the bad use of malloc. Searching google I see that UnicodeString seems to be an object from Object Pascal, is it? Really seems a non-POD and you will run into trouble anyway, don't use malloc for C++ objects.
Your while loop code is fine (though coded oddly, and inefficiently).
Chances are, you are invoking undefined/illegal behavior elsewhere in the code, and that is likely affecting the while loop as a side effect.
For instance, DO NOT use malloc()/free() in C++, use new/delete instead. Your TDoubleLinkedList struct contains a Name member that is clearly a non-POD class type, as it is being assigned a UnicodeString value. That member's constructor will NOT be run when using malloc() to allocate the TDoubleLinkedList instance, thus invoking undefined behavior when the Name parameter is assigned to the ReturnNode->Name member.
That being said, you should get rid of CreateNode() entirely, and instead add a proper constructor to TDoubleLinkedNode itself, eg:
struct TDoubleLinkedNode
{
int ID;
UnicodeString Name;
TDoubleLinkedNode *ptr_PriorNode;
TDoubleLinkedNode *ptr_NextNode;
TDoubleLinkedNode(int id, UnicodeString name, TDoubleLinkedNode *priorNode = NULL, TDoubleLinkedNode *nextNode = NULL) :
ID(id),
Name(name),
ptr_PriorNode(priorNode),
ptr_NextNode(nextNode)
{
}
};
And then Add_ToEnd() can be simplified:
void __fastcall TDoubleLinkedList::Add_ToEnd ( int ID,
UnicodeString Name
)
{
TDoubleLinkedNode* newNode = new TDoubleLinkedNode(ID, Name);
if (!FHeadNode)
{
// Head Pointer has not been initialised. Set as newNode
FHeadNode = newNode;
return;
}
TDoubleLinkedNode* tempNode = FHeadNode;
while (tempNode->ptr_NextNode) {
tempNode = tempNode->ptr_NextNode; // Move to the "Next" record
}
tempNode->ptr_NextNode = newNode;
newNode->ptr_PriorNode = tempNode;
}
Which can actually be simplified much further:
void __fastcall TDoubleLinkedList::Add_ToEnd ( int ID,
UnicodeString Name
)
{
TDoubleLinkedNode** tempNode = &FHeadNode;
while (*tempNode) {
tempNode = &((*tempNode)->ptr_NextNode);
}
*tempNode = new TDoubleLinkedNode(ID, Name, *tempNode);
}
And more so if you add a FTailNode member to your class:
void __fastcall TDoubleLinkedList::Add_ToEnd ( int ID,
UnicodeString Name
)
{
TDoubleLinkedNode **tempNode = (FTailNode) ? &(FTailNode->ptr_NextNode) : &FHeadNode;
FTailNode = new TDoubleLinkedNode(ID, Name, FTailNode);
*tempNode = FTailNode;
}
That being said, a better solution is to not create a linked list manually at all. Use the standard std::list container in the <list> header, eg:
#include <list>
struct TNodeData
{
int ID;
UnicodeString Name;
};
class TDoubleLinkedList
{
private:
std::list<TNodeData> FData;
public:
...
void __fastcall Add_ToEnd(int ID, UnicodeString Name);
...
};
void __fastcall TDoubleLinkedList::Add_ToEnd ( int ID,
UnicodeString Name
)
{
FData.push_back(TNodeData{ID, Name});
}

Cycle remove from linklist gives segmentfault

void removeLoop(Node* head)
{
// code here
// just remove the loop without losing any nodes
Node* rab=head;
Node* tur=head;
while(rab && rab->next)
{
rab=rab->next->next;
tur=tur->next;
if(tur==rab)
break;
}
Node* temp=NULL;
if(rab && rab->next)
{
rab=head;
while(rab!=tur)
{
rab=rab->next;
temp=tur;
tur=tur->next;
}
temp->next=NULL;
}
}
This is my code implemented using floyd algo.
Question link
https://practice.geeksforgeeks.org/problems/remove-loop-in-linked-list/1#
It is giving segment fault on submission not able to identify the particular test case it's failing
According to question no need to return anything.
If we take the input as
4
1 2 3 4
1
then it will show the segmentation error.
Reason: If you run the code on this specific testcase, then after running the first while loop, both tur and rab will point to the head of the list. Now the condition of while loop inside the if loop will always return false. And after that, the code on the next line temp->next=NULL will give error because temp was initially NULL and this line will exhibit undefined behavior.
The correct program should be:
void removeLoop(Node* head)
{
Node* rab=head;
Node* tur=head;
while (rab && rab->next) {
rab = rab->next->next;
tur = tur->next;
if (rab == tur)
break;
}
if (tur == rab)
{
tur = head;
if(tur == rab) {
while(rab->next != tur) rab = rab->next;
}
else {
while (tur->next != rab->next) {
rab = rab->next;
tur = tur->next;
}
}
rab->next = NULL;
}
}

Trouble inserting BST node into a List node

I'm creating a customer loyalty program type code using a Linked list and BST's. It uses a list of loyalty programs, each node containing a BST of customer ID's. Currently I am attempting to create a function that searches the list for a loyalty program, once found (creates if not) adds the customer ID into the BST of that node. However when testing, im running into a reading violation on the insert new list node (insert_at_front) function.
Any help would be greatly appreciated!
Ive tried altering the function type of the find_list function and creating wrapper functions for it as I have previously done with similar functions for BST's, but I keep getting lost in the code and it seems to break it more.
list.h header file:
typedef struct listNode {
char* name; //Name of company
BST *customer; //Tree of customer ID's
struct listNode *next; //Pointer for next compnay
} *ListNodePtr;
void option_insert(List *self) {
char* input_loyalty;
int input_ID;
printf("What loyalty program do you wish to add a customer to? \n");
scanf("%s", &input_loyalty);
printf("What is the customer ID \n");
scanf("%d", &input_ID);
find_list(self, input_loyalty, input_ID);
}
void find_list(List *self, char* data, int ID) {
ListNodePtr current = self->head;
if (current != NULL) {
if (current->name == data) {
insert_bst(self->head->customer, ID);
}
else {
current = current->next;
}
}
else {
insert_at_front(self, data);
insert_bst(self->head->customer, ID);
}
}
void insert_at_front(List *self, char* data) {
int n = strlen(data);
ListNodePtr new_node = malloc(n * sizeof(char*));
strcpy(new_node->name, data);
new_node->next = self->head;
self->head = new_node;
}
I have included the functions being utilised in the problem but note that they are separated in different .c files. (however this should cause no difference) and I can certainly provide more code if needed
The answer is probably in your use of malloc(). You are creating memory based off the size of data, and not the size of a struct.
I should also mention that if you are using C++ (and not C) it is probably better to learn how to use the new keyword instead.
Anyway, if you still decide to use malloc, try this instead:
void insert_at_front(List *self, char* data) {
int n = strlen(data);
ListNodePtr new_node = malloc(sizeof(listNode)); // note, we're using the size of a node instead
new_node->name = malloc(n * sizeof(char)); // now, we need to allocate the string too.
strlcpy(new_node->name, data, n); // if you want to use a "secure" copy
new_node->next = self->head;
self->head = new_node;
}

Segmentation fault bintree

I'm trying to implement the bintree, but I have problems in the insert method.
If I add the first element, the program dont crash but, when I introduce 2 or more element the program crash.
This is the code
template <typename T>
void Arbol<T>:: insertar( T c){
if(laraiz==0)
{
laraiz=new celdaArbol;
laraiz->elemento=c;
laraiz->padre=laraiz->hizqu=laraiz->hder=0;
}
else {
celdaArbol *com=laraiz;
bool poner=false;
while(poner==false){
if(c>com->elemento){
if(com->hder==0){
com->hder= new celdaArbol;
com->hder->elemento=c;
com->hder->padre=com;
poner=true;
}
else{
com=com->hder;
}
}
else {
if(com->hizqu==0){
com->hizqu= new celdaArbol;
com->hizqu->elemento=c;
com->hizqu->padre=com;
poner=true;
}
else {
com=com->hizqu;
}
}
}
}
}
I think that the problem is in the else:
else{
com=com->hizqu; //com=com->hder;
}
Because I saw in the debugger that the program enter several times in the section and should not do.
According to this code:
laraiz->padre=laraiz->hizqu=laraiz->hder=0;
You do not properly intialize pointers hizqu and hder to nullptr in constructor of celdaArbol class. And you do not initialize them in either branch of if(c>com->elemento){ so they seem to have garbage values.
Also your code can become more readable and less error prone if you use proper C++ constructions:
celdaArbol *com=laraiz;
while( true ){
celdaArbol *&ptr = c > com->elemento ? com->hder : com->hizqu;
if( ptr ) {
com = ptr;
continue;
}
ptr = new celdaArbol;
ptr->elemento=c;
ptr->padre=com;
ptr->hder = ptr->hizqu = nullptr;
break;
}
This code is logically equal to yours, except it shorter, easier to read, avoid duplication and fixes your bug.
For every leaf node (except the root of the tree), you never initialize the left child or right child node to be anything but an unspecified value.
You probably meant to initialize them as nullptr.
Here's one example:
if (com->hizqu==0){
com->hizqu = new celdaArbol;
com->hizqu->elemento = c;
com->hizqu->padre = com;
poner = true;
// What is the value of com->hizqu->hizqu?
// What is the value of com->hizqu->hder?
}

Interview Coding - Take a pointer to a Node structure as a parameter and return a complete copy of the passed-in data structure

This is an interview question that I found interesting.
Write a method that takes a pointer to a Node structure as a parameter and returns a complete copy of the passed-in data structure.
The Node structure contains two pointers to other Node structures.
For example, the method signature could look like so:
Node* Copy(Node* root);
Note - Do not make any assumptions about the data structure – it could be a tree, linked list, graph, etc.
How can this be done for any data structure ?
In the generic graph case, you need a mapping from nodes in the original graph to nodes in the new graph, so that when a cycle is encountered, the proper link gets created. If you happen to have extra temporary space in each node, large enough to hold a pointer, then you can store the mapping directly in the nodes; otherwise, you'll need to use an external map, such as an associative array or hash table.
Then it's just a matter of traversing the graph, copying nodes, and looking up the corresponding edges. Something like this:
struct Node
{
Node(int _data) : data(_data) { memset(links, 0, sizeof(links)); }
int data;
Node *links[2];
}
Node *Copy(Node *root)
{
typedef std::map<Node*, Node*> NodeMap;
NodeMap nodeMap;
std::deque<Node*> nodesToVisit;
// Set up initial new root and mapping for the root
Node *newRoot = new Node(root->data);
nodeMap[root] = newRoot;
// Breadth-first search the graph
nodesToVisit.push_back(root);
while(!nodesToVisit.empty())
{
Node *cur = nodesToVisit.front();
nodesToVisit.pop_front();
Node *newCur = nodeMap[cur];
for(int i = 0; i < 2; i++)
{
Node *link = cur->links[i];
if(link)
{
// If we've already created the corresponding node for this
// link, use that. Otherwise, create it and add it to the map.
NodeMap::iterator mappedLink = nodeMap.find(link);
if(mappedLink != nodeMap.end())
{
newCur->links[i] = mappedLink->second;
}
else
{
Node *newLink = new Node(link->data);
nodeMap[link] = newLink;
newCur->links[i] = newLink;
nodesToVisit.push_back(link);
}
}
}
}
return newRoot;
}
The problem as stated is impossible. You have to assume that the entire data structure is stored entirely within the content of nodes that are accessible from that initial one. But that is not an assumption you are allowed to make. Even your standard basic double linked list might not fit that description.
class Copier {
std::map <Node*, Node*> copies;
Node* Copy(Node* n) {
if (!n) return 0;
Node*& copy = copies[n];
if (!copy) {
copy = new Node();
copy.node1 = Copy(n.node1);
copy.node2 = Copy(n.node2);
}
return copy;
}
}
Node* Copy(Node* root) {
if (root == NULL)
return root;
std::unordered_map<Node*, Node*> completed;
std::deque<Node*> todo;
Node *ret = new Node(*scur);
completed.push_back(std::make_pair(root, ret));
todo.push_pack(root);
//while there's more nodes to duplicate
do {
//duplicate the node
Node* oldNode = todo.back();
Node* newNode = completed[cur];
todo.pop_back();
if(oldNode->left) {
auto iter = completed.find(oldNode->left);
//if it has a left child that needs duplicating, add it to the todo list
if (iter == completed.end()) {
newNode->left = new Node(*(oldNode->left));
completed.push_back(std::make_pair(oldNode->left, newNode->left));
todo.push_back(oldNode->left);
} else {
newNode->left = completed[oldNode->left];
}
}
if(oldNode->right) {
auto iter = completed.find(oldNode->right);
//if it has a right child that needs duplicating, add it to the todo list
if (iter == completed.end()) {
newNode->right = new Node(*(oldNode->right));
completed.push_back(std::make_pair(oldNode->right, newNode->right));
todo.push_back(oldNode->right);
} else {
newNode->right= completed[oldNode->right];
}
}
} while(todo.empty() == false)
//return the translation of the root
return ret;
}
Doesn't have stack overflow, root can be NULL, doesn't fail if left or right are NULL.
[Edit]Adam Rosenfield made me realize this was incorrect if there was loops in the network. Had to rewrite almost from scratch. Due to the large amount of code required, I prefer his code's for loop.
return new Node(*node);
Trick question?
You should write it recursively;
Node * Copy( Node * root )
{
Node * node_copy;
node_copy = new Node; // Assume Node1 and Node2 are initialized to 0
node_copy->content = root->content;
if( root->Node1 ) node_copy->Node1 = Copy( root->Node1 );
if( root->Node2 ) node_copy->Node2 = Copy( root->Node2 );
return node_copy;
}
So, this does not make any assumption on the data type
Given that a copy constructor exists that copies only the contents of a node and not its children:
Node* Copy(Node* root)
{
Node* copy = new Node(*root);
copy->left = Copy(root->left);
copy->right = Copy(root->right);
return copy;
}
In a more general sense, I would use copy-constructors that fully copy the entire data structure:
Node* Copy(Node* root)
{
return new Node(*root);
}