c++ pass a custom struct through a function - c++

I have been working with this C++ program for a while, and I have figured what exactly is happening, but I haven't figured out how to fix it exactly. Here is what I have set up:
struct entry {
string foo;
string bar;
string num;
};
struct node {
entry input;
node* left;
node* right;
};
node* home = new node;
This code takes place in a separate header file that is included in a main cpp file, which has the following:
home->input.foo="John";
home->input.bar="Doe";
home->input.name="1234";
printAll(home);
This is were the error pops up, trying to pass home through the function printAll in the header file:
void printAll(node* start){
if(start==NULL) return;
printAll(start->left);
cout << start->input.foo;
printall(start->right);
}
The error that Visual Studio gives me is 0xCDCDCDCD on start. I understand it's not home that is causing the issue, it's start, but I don't understand how to correct this error. I read around and I can assume that start has been thrown into heap memory but it is unintalized. I didn't think this was possible. And I also can guess that C++ doesn't know what start is and how to use it, how would I correct this?

You haven't initialized left or right. In debug builds, Visual Studio will set uninitialized memory to 0xCDCDCDCD. This is obviously not equal to NULL, so your comparison returns false.

As noted in the other answer, the error you are getting may be because you haven't initialized the left and right node as NULL. However you have another error and that is you have created an infinite loop in your printAll.
Your printAll function will first move to the left-most node and print it. After that it will move one node to the right, and, before prints it anything, it'll move to the left again.
The proper way of printing all the nodes is to put list of nodes within a class that keeps track of the first and last node.
Class LList {
node * startNode;
void printAll(){
if (startNode == NULL)
return;
node * currNode = startNode;
// print all the nodes moving left to right
_printAll(currNode);
}
void _printAll(currNode){
// print currNode and recursively go to next by calling
// _printAll(currNode->right)
}
}
Additional things to note
Of course, you'll want to make printAll public and the rest of the
above private.
You'll also need a function to add a node to the list. Look up linked lists attributes and methods to see what else you'll need.
It's better to avoid structs and use objects in place of them

Related

Tree traversal falls into infinite loop (with huffman algorithm implementation)

I am trying implementing the huffman algorithm following the steps described in this tutorial: https://www.programiz.com/dsa/huffman-coding, and so far I got this code:
void encode(string filename) {
List<HuffmanNode> priorityQueue;
List<Node<HuffmanNode>> encodeList;
BinaryTree<HuffmanNode> toEncode;
//Map<char, string> encodeTable;
fstream input;
input.open(filename, ios_base::in);
if (input.is_open()) {
char c;
while (!input.eof()) {
input.get(c);
HuffmanNode node;
node.data = c;
node.frequency = 1;
int pos = priorityQueue.find(node);
if(pos) {
HuffmanNode value = priorityQueue.get(pos)->getData();
value++;
priorityQueue.update(pos, value);
} else {
priorityQueue.insert(node);
}
}
}
input.close();
priorityQueue.sort();
for(int i=1; i<=priorityQueue.size(); i++)
encodeList.insert( priorityQueue.get(i) );
while(encodeList.size() > 1) {
Node<HuffmanNode> * left = new Node<HuffmanNode>(encodeList.get(1)->getData());
Node<HuffmanNode> * right = new Node<HuffmanNode>(encodeList.get(2)->getData());
HuffmanNode z;
z.data = 0;
z.frequency = left->getData().frequency + right->getData().frequency;
Node<HuffmanNode> z_node;
z_node.setData(z);
z_node.setPrevious(left);
z_node.setNext(right);
encodeList.remove(1);
encodeList.remove(1);
encodeList.insert(z_node);
}
Node<HuffmanNode> node_root = encodeList.get(1)->getData();
toEncode.setRoot(&node_root);
}
full code for the main.cpp here: https://pastebin.com/Uw5g9s7j.
When I try run this, the program read the bytes from the file, group each character by frequency and order the list, but when I try generate the huffman tree, I am unable to traverse this tree, always falling into a infinte loop (the method get stuck in the nodes containing the 2 first items from the priorityQueue above).
I tried the tree class with BinaryTree<int>, and everything works fine in this case, but with the code above the issue happens. The code for the tree is this (in the code, previous == left and next == right - I am using here the same Node class already implemented for my List class): https://pastebin.com/ZKLjuBc8.
The code for the List used in this example is: https://pastebin.com/Dprh1Pfa. And the code for the Node class used for both the List and the BinaryTree classes is: https://pastebin.com/ATLvYyft. Anyone can tell me what I am missing here? What I am getting wrong here?
UPDATE
I have tried a version using only c++ stl (with no custom List or BinaryTree implementations),but the same problem happened. The code is that: https://pastebin.com/q0wrVYBB.
Too many things to mention as comments so I'm using an answer, sorry:
So going top to bottom through the code:
Why are you defining all methods outside the class? That just makes the code so much harder to read and is much more work to type.
Node::Node()
NULL is C code, use nullptr. And why not use member initialization in the class?
class Node {
private:
T data{};
Node * previous{nullptr};
Node * next{nullptr};
...
Node::Node(Node * node) {
What is that supposed to be? You create a new node, copy the value and attach it to the existing list of Nodes like a Remora.
Is this supposed to replace the old Node? Be a move constructor?
Node::Node(T data)
Write
Node<T>::Node(T data_ = T{}) : data{data_} { }
and remove the default constructor. The member initialization from (1) initializes the remaining members.
Node::Node(T data, Node * previous, Node * next)
Again creating a Remora. This is not inserting into an existing list.
T Node::getData(), void Node::setData(T value)
If everyone can get and set data then just make it public. That will also mean it will work with cons Node<T>. Your functions are not const correct because you lack all the const versions.
Same for previous and next. But those should actually do something when you set the member. The node you point to should point back to you or made to do so:
void Node::setPrevious(Node * previous) {
// don't break an existing list
assert(this->previous == nullptr);
assert(previous->next == nullptr);
this->previous = previous;
previous->next = this;
}
Think about the copy and move constructors and assignment.
Follow the rule of 0/3/5: https://en.cppreference.com/w/cpp/language/rule_of_three . This goes for Node, List, ... all the classes.
List::List()
Simpler to use
Node<T> * first{nullptr};
List::~List()
You are deleting the elements of the list front to back, each time traversing the list from front till you find index number i. While horrible inefficient the front nodes have also already been deleted. This is "use after free".
void List::insert(T data)
this->first = new Node<T>();
this->first->setData(data);
just write
first = new Node<T>(data);
And if insert will append to the tail of the list then why not keep track of the tail so the insert runs in O(1)?
void List::update(int index, T data)
If you need access to a list by index that is a clear sign that you are using the wrong data structure. Use a vector, not a list, if you need this.
void List::remove(int index)
As mentioned in comments there are 2 memory leaks here. Also aux->next->previous still points at the deleted aux likely causing "use after free" later on.
int List::size()
Nothing wrong here, that's a first. But if you need this frequently you could keep track of the size of the list in the List class.
Node * List::get(int index)
Nothing wrong except the place where you use this has already freed the nodes so this blows up. Missing the const counterpart. And again a strong indication you should be using a vector.
void List::set(int index, Node * value)
What's this supposed to do? Replace the n-th node in a list with a new node? Insert the node at a specific position? What it actually does it follow the list for index steps and then assign the local variable aux the value of value. Meaning it does absolutely nothing, slowly.
int List::find(T data)
Why return an index? Why not return a reference to the node? Also const and non-const version.
void List::sort()
This code looks like a bubblesort. Assuming it wasn't totaly broken by all the previous issues, would be O(n^4). I'm assuming the if(jMin != i) is supposed to swap the two elements in the list. Well, it's not.
I'm giving up now. This is all just the support classes to implement the BinaryTree, which itself is just support. 565 lines of code before you even start with your actual problem and it seems a lot of it broken one way or another. None of it can work with the state Node and List are in. Especially with copy construction / copy assignment of lists.

C++ Binary Tree recursive destructor issue

I made a binary tree class which holds:
int value, BinaryTree* left, BinaryTree* right.
class BinaryTree {
private:
int value;
BinaryTree* left;
BinaryTree* right;
bool isVisited;
public:
BinaryTree();
BinaryTree createComplete(int n);
~BinaryTree();
}
My destructor is :
BinaryTree::~BinaryTree() {
delete left;
delete right;
}
When running in clion it works perfectly, but in my terminal I get
a segfault (core dumped). Everywhere I looked people claimed that this should be the destructor. Any elaboration would help!
I am not a stackoverflow expert , I updated my ~BinaryTree function to still gets a segfault :
BinaryTree::~BinaryTree() {
if (right != NULL) {
delete right;
}
if (left != NULL) {
delete left;
}
}
First of all your current implementation is not that of a complete tree.
It is a node, thus I suggest renaming it to BinaryTreeNode and using it to construct a new class BinaryTree, that keeps track of the root and allows you to recursively deallocate the tree.
Having said that your destructor most likely segfaults because you are blindly attempting to delete a pointer.
First make sure you initialize left and right to nullptr.
Then you do if(left != nullptr) { delete left }
Without seeing your constructor, I assume you don't initialize your node's children to NULL. That might mean that the uninitialized nodes left and right at the bottom leaves have a random value in them. When the destructor runs, it will try to free the memory that the random garbage in the nodes point to.
Try initializing your child nodes to NULL when ctoring nodes, then making a check for it like monoceres suggested. It will also be good to set the pointer to NULL after delete to avoid situation of erronous double delete
So after debugging I noticed that the every right child is loosing it's nodes , which while going in a pre order traversal is fine , but when deleting it casuing the problem , thanks for the help every one !

How can I verify a node is deallocated in a C++ Linked List?

I have Xcode and I would like to know how I can verify if my nodes were correctly deleted/deallocated. I am sure I'm going about it in the wrong way.
What I'm doing is printing data off of whatever ptrDel is pointing at, then use Delete to free it, and checking to see if I can view it again (and Yes, I still can). I thought this block of memory would be "zeroed" out or filled with something that doesn't have the old data. Why is it still possible to view what's there? Shouldn't I get a "bad memory access" error from XCode?
Here's my struct
struct Node {
int data;
Node* next;
};
.......
bool deleteNode(Node **head, Node *ptrDel) {
Node *cur = *head;
printf("deleteNode top %d \n", ptrDel->data); //"deleteNode top a" would be the output for example
if(ptrDel == *head) {
*head = cur->next;
delete ptrDel;
printf("deleteNode 2 %d \n", ptrDel->data); //"deleteNode top a" would be the output
return true;
}
while(cur) {
if(cur->next == ptrDel) {
cur->next = ptrDel->next;
delete ptrDel;
printf("deleteNode 2 %d \n", ptrDel->data); //"deleteNode top a" would be the output
return true;
}
cur = cur->next;
}
return false;
}
How else can I delete a node? I don't want my suddenly unlinked node from my first Linked list to be floating around in the system. What if there was important sensitive information in that node? Shouldn't it be filled up with some other data and placed back into free memory?
Thank you.
Memory that has been freed with delete is typically not changed at all. You could do something like ptrDel->next = NULL after you have unlinked it, to avoid it producing a valid chain later.
There is no direct way, other than code-review by someone that understands the code, to ensure that your code is correct - of course, a set of good tests is also useful to ensure your code works (you can for example insert a number of elements, delete some of them and see if you can "search" in your list for them - they should be there before the delete, and not after), and you can create long lists and delete again (several thousand items and several thousand times over), and ensure that your overall memory usage isn't going up between the first and the last iteration of the outer loop.
Tools such as Valgrind can also be used to identify where/if you are leaking memory.

Geting Data from a Tree Structure

I have a tree structure that i am creating the following way. The tree is created correctly as far as i know. But when i want to get the data from a node, i get some weird acsii symbols.
How I set the data.Lets say its empty. Doesn't matter at the moment. I have a value in my program. The function feeds itself until i get to the end of the data.
struct Node {
char Data;
Node* Left;
Node* Right;
};
Node maketree(0,s,split)
{
Node node;
node.Data=' ';
Node n1=subsplit(0,s,splitingat);
Node n2= subsplit(1,splitingat+1,e);
node.Left=&n1;
node.Right=&n2;
return node;
}
This is how i get data from the tree.
char decode(Node node,string text)
{
int currentindex=0;
Node sub=node;
{
}
if(text[currentindex]=='0')
{
sub=*sub.Left;
cout<<" x "<<sub.Data<<endl;
}
else if(text[currentindex]=='1')
{
sub=*sub.Right;
cout<<" x "<<sub.Data<<endl;
}
// cout<<sub.Data<<endl;
}
I think that the mistake is that I am printing out the pointer and not the node. But I don't know where I went wrong.
The source of your problem appears to be here:
Node node;
node.Data=' ';
Node n1=subsplit(0,s,splitingat);
Node n2= subsplit(1,splitingat+1,e);
node.Left=&n1; // danger Will Robinson!
node.Right=&n2;
return node;
You're taking the addresses of local, temporary, automatic variables and storing them in pointers that you return through node. As soon as that return executes, n1 and n2 are destroyed and node.Left and node.Right are left pointing to garbage. You may be able to fix this like so:
Node* n1=new Node(subsplit(0,s,splitingat));
Node* n2=new Node(subsplit(1,splitingat+1,e));
// side note: probably better to have subsplit() return dynamically-allocated Node*s to avoid the copy
node.Left=n1;
node.Right=n2;
but you may still have issues crop up if similar things are being done elsewhere.
Kind of along the same lines, in your second block of code, you are making a copy of each node you examine and storing it into sub. It would probably make more sense to have sub be a Node*.
And finally, to avoid memory management issues (almost) altogether, use shared_ptr<Node> instead of Node* in all of the above. :)

double linked list and its deletion

i wrote the following code to delete the nodes at the beginning and at the end of a doubly linked list....but the execution of these functions stopped in between and the program was aborted......
struct nodeb
{
int value;
nodeb *next;
nodeb *pre; //pre of first node and next of last node point to null...
nodeb(int a,nodeb *ptr1=0, nodeb *ptr2=0):value(a), next(ptr1), pre(ptr2)
{}
};
class doublelist
{
private:
nodeb *head1,*head2;
public:
doublelist():head1(0),head2(0)
{cout<<"double list created"<<endl;}
void deletebeg()//delete beginning node
{
if(head1->next==0)
{
nodeb *ptr=head1;
head1=head2=0;
delete ptr;
}
else
{
nodeb *ptr=head1->next;
nodeb *ptr1=head1;
ptr->pre=0;
head1=ptr;
delete ptr1;
}
}
void deleteend()//delete end node
{
nodeb *ptr=head1;
nodeb *ptr1;
while(ptr->next!=0)
{
ptr1=ptr;
ptr=ptr->next;
}
delete ptr;
ptr1->next=0;
}
}; //class ends here
int main()
{
doublelist list1;
nodeb node(8);
nodeb node1(7);
nodeb node2(9);
nodeb node3(4);
list1.insertbeg(node);
list1.insertbeg(node1);
list1.insertafter(node3,1);
list1.insertend(node2); //insertbeg,insertafter and insertend are three functions i defined to attach nodes at the beginning,at a particular location and at the end of the list
list1.deletebeg();
}
can anyone please tell me the problem??this is the link to the three functions for insertions
Now I can see all the code the problem is very simple. Your deletebeg function is deleting the beginning node with delete, but you didn't allocate the node with new. You should only delete memory if you created it using new.
Normally when people write linked list classes they allocate the nodes inside the list methods using new. Then they can safely delete the nodes inside the methods. You are doing the deletes but you are not using new. So you need to rewrite your main function like this
int main()
{
doublelist list1;
list1.insertbeg(8); // add 8 to beginning of list
list1.insertbeg(7); // add 7 to beginning of list
list1.insertafter(4,1); // add 4 after first item of list
list1.insertend(9); // add 9 to end of list
list1.deletebeg();
}
Then you need to rewrite your methods like this
void insertbeg(int value)//insert beginning
{
nodeb* a = new nodeb(value); // allocate node inside of method using new
if(head1==0)
{
head1=a;
head2=a;
a->next=0;
a->pre=0;
}
else
{
nodeb *ptr=head1;
ptr->pre=a;
a->pre=0;
a->next=ptr;
head1=a;
}
}
I've only shown insertbeg, you need to change all your insert methods in the same way.
I'm not promising that's the only problem, but make this change and you'll be on the right way. If you have more problems then post again, but remember post complete code. It's the only way you'll get help with problems like this.
I'm a little baffled by this code excerpt, but I'll assume this is the entire excerpt for this...
The functions deletebeg and deleteend aren't declared anywhere in the class definition, only after it. Normally, it would look something like:
class List{
void aFunction(List * argument);
};
void List::aFunction(List * argument){
do something
};
But all that aside, do not make your own linked list, it is much faster and will make your life easier using std::list<int> (replacing int with whatever data type you are making a list for).
There are lots of reasons for this, but the main one is that you only don't have to write it, but you don't have to debug it either. The linked list implementation you created, for instance, uses a recursive function to delete itself (when a function calls itself, it's recursive). If the linked list is very large, this can cause a stack overflow, caused by calling too many functions within functions. It's things like this that are a nightmare to track down and find, and distract you from the real reason you are programming. That is assuming that reason isn't making a linked list. :P
While it isn't usual to see functions declared outside a class in C++, it isn't impossible. But that would mean that head1 is a global variable somewhere that isn't shown.
You left out the part of that is actually calling deletebeg and deleteend so it is hard to tell exactly what is happening. Perhaps you are making use of a pointer after it has been deleted.
Also, while NULL is usually zero, there is no guarantee that is the case for your compiler. You should be using NULL instead of zero.
My guess is that you called deleteend with a node that for whatever reason had head1==0, then ptr1 was never initialized, and the program crashed on the last line of deleteend when you tried to dereference the uninitialized pointer.
Further to the comments on my previous answer
This code is wrong
void insertbeg(int value)//insert beginning
{
nodeb a(value); // create node on the stack
if(head1==0)
{
head1=&a;
head2=&a;
a.next=0;
a.pre=0;
}
else
{
nodeb *ptr=head1;
ptr->pre=&a;
a.pre=0;
a.next=ptr;
head1=&a;
}
}
The code above would have the problem you described, when you said 'head1 and head2 will point nowhere'. But this code is completely different
void insertbeg(int value)//insert beginning
{
nodeb* a = new nodeb(value); // allocate node inside of method using new
if(head1==0)
{
head1=a;
head2=a;
a->next=0;
a->pre=0;
}
else
{
nodeb *ptr=head1;
ptr->pre=a;
a->pre=0;
a->next=ptr;
head1=a;
}
}
It's different because it uses new to create the objects. When you use new the objects don't get destroyed when you exit the function. That's what new means. But when you do use new you also have to use delete when you have finished with the nodes.