I'm having a little trouble with a critical function in my program, I've put bug testing lines everywhere and singled it down to a single if statement"
template <typename Item>
bool BTNode<Item>::isNull(string leftOrRight)
{
std::cout<<"Is NULL test outer."<<endl;
bool returnNullTest = true;
if (leftOrRight == "left")
{
std::cout<<"Is NULL test inner 1."<<endl;
if (left != NULL)
{
returnNullTest = false;
}
}
else if (leftOrRight == "right") //.c_str()
{
std::cout<<"Is NULL test inner 2."<<endl;
if (right != NULL)
{
returnNullTest = false;
}
}
std::cout<<"NULL TEST FINISHED."<<endl;
return returnNullTest;
}
this is the output:
Is NULL test outer.
Is NULL test inner 2.
Segmentation fault (core dumped)
this is the definition of 'left' and 'right':
BTNode<Item>* left;
BTNode<Item>* right;
in the constructors for BTNode 'left' and 'right' are defined as:
left = NULL;
right = NULL;
does anyone have an idea as to where i'm going wrong with this, i've tried the line
if (left == NULL)
and
if (right == NULL)
with the Boolean switched around but I got the same error.
this is 'BTNode.h'
#ifndef matt_BTNode
#define matt_BTNode
#include <cstdlib>
namespace mattassign3{
template <typename Item>
class BTNode
{
private:
Item* data;
BTNode<Item>* left;
BTNode<Item>* right;
public:
BTNode();
BTNode(Item* startingData);
~BTNode();
BTNode<Item>* getLeft();
BTNode<Item>* getRight();
Item* getData();
bool isNull(string leftOrRight);
void setLeft(BTNode<Item>* leftToSet);
void setRight(BTNode<Item>* rightToSet);
void printInclData();
float comparableNumber();
string comparableString();
};
}
#include "BTNode.template"
#endif
Most likely this is an invalid pointer. The function crashed the first time a member of this was accessed. Try printing this along with the first message.
The fact that you crash when accessing "right" is a symptom of a bug higher in your call stack. Specifically, prior to arriving at this point in your program you must have done something like, e.g.
BNode* node = something->getRight();
node->isNull();
You need to remind yourself that in your isNull function right and left are member variables. Their locations in memory are relative to the instance of BNode they belong to, they are not just some local variables (this is another good reason why many programmers choose to distinguish member variables with a prefix like "m_", e.g. "m_left", "m_right").
If the "BNode*" pointer you are calling "isNull" against is bad, then it helps to remember that when you say
if(left != NULL)
you are accessing *(this + 4 bytes). You're "getting away" with access "left", but "right" is unfortunately on the other side of some kind of memory boundary that results in your crash.
Make sure: Your constructors assign default values to these pointers, that you check return values from getLeft() and getRight() before derefencing them, that your copy constructor does NOT copy these values (that would mean there are two Nodes that think they are at the same position in the tree) and that your destructor either asserts if the node is not unlinked or unlinks the node.
Related
I am new to C++. I expected two pointers that don't point to anything to be detected as null pointers. However this works only with one of them. The physical addresses of those pointers are somewhat different - 0xe00000001 vs 0x0 (this one is properly detected as null pointer).
I've written the following snippet of code:
#include <iostream>
using namespace std;
struct TNode {
TNode* Parent; // Pointer to the parent node
TNode* Left; // Pointer to the left child node
TNode* Right; // Pointer to the right child node
int Key; // Some data
};
int main() {
TNode parent;
parent.Key = 2;
TNode first;
first.Key = 1;
first.Parent = &parent;
parent.Left = &first;
cout << first.Left << endl; // get 0xe00000001 here
cout << first.Right <<endl; // get 0x0
if (first.Right == nullptr) {
cout <<"rnull"<<endl; // rnull
}
if (first.Left == nullptr) {
cout <<"lnull"<<endl; // nothing
}
return 0;
}
What is going on here? Basically, I want to find a way to check whether first.Left points to nothing.
In your example, first.Left and first.Right are uninitialized, not null. This means that they basically contain whatever garbage was on the stack at the time they were allocated. Accessing the actual value (by printing the pointer, for example) is actually undefined behavior, but with most compilers on low optimization settings it'll just print that garbage.
Solution 1: give default values to member variables
If you want them to be null, you can modify TNode so that their initial value is guaranteed to be null:
struct TNode {
TNode* Parent = nullptr;
TNode* Left = nullptr;
TNode* Right = nullptr;
int Key = 0;
};
int main() {
TNode n; //Everything initialized to null or 0
}
This will guarantee that they're null.
Solution 2: Define TNode() to initialize members
Alternatively, you could also explicitly define the constructor so that it makes everything null
struct TNode {
TNode* Parent, Left, Right;
// Everything gets default-initialized to null
TNode() : Parent(), Left(), Right() {}
};
int main() {
Tnode n; // Everything initialized to nullptr or 0
}
Solution 3: default-initialize at the point of use
Even if you don't explicitly define a constructor, everything gets initialized to 0 (or null, if it's a pointer) when you explicitly initialize it by putting {} when declaring the variable.
struct TNode {
TNode* Parent, Left, Right;
int Key;
};
int main() {
TNode iAmUninitialized; // This one is uninitialized
Tnode iAmInitialized{}; //This one has all it's members initialized to 0
}
First of all, in C and C++ there is no such thing as a pointer that points to nothing. Regardless of the value in the pointer, it points at something. Even NULL is a pointer to address "0" but we use that, by convention to represent a NULL. The problem with a pointer that is uninitialized is that it can point to anything and that anything is likely an illegal address which will cause an exception or it points to something else in the application and, if the data is modified, will cause an undesired side-effect.
In your case the 2nd pointer is 0x00 and that is NULL. The 1st pointer, however, is 0x01, and that is NOT NULL.
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 !
Right now I'm working on a LinkedList project, with the clear method acting very strangely at the moment:
template <class Elm>
void LinkedSortedList<Elm>::clear() {
if (head != NULL) {
LinkedNode<Elm>* currentNode = head;
LinkedNode<Elm>* nextNode;
if (head->next != NULL) {
nextNode = head->next;
}
while (currentNode != NULL) {
nextNode = currentNode->next;
delete currentNode;
currentNode = nextNode;
}
head = NULL;
}
}
Everything appears to work properly until the line
nextNode = currentNode->next;
where both currentNode's and nextNode's values are switched to two completely different, extremely large values. Before that line, both variables have the proper values in them. When
delete currentNode;
is called in the next line, I immediately get a segfault, even though it doesn't look like the address of the node was changed in any way.
Is there anything that might be causing the pointers to point to two completely different places all of the sudden?
EDIT: Here's the LinkedNode class,
#ifndef _LinkedNodeClass_
#define _LinkedNodeClass_
#include <iostream>
using namespace std;
template <class Elm> class LinkedNode {
public:
Elm value; // The data value
LinkedNode *next; // Pointer to the next node
// Simple inline constructor: initialize values
LinkedNode(Elm newval = 0, LinkedNode* newptr = NULL)
{value = newval; next = newptr;}
~LinkedNode() {delete &next;}
// Inline print function: print the node's value
void print() {cout << value;}
};
#endif
Is there anything that might be causing the pointers to point to two completely different places all of the sudden?
Yes! If you don't have LinkedNode<T>::next initialized to NULL correctly in the class constructors or assignment operators, they might hold an uninitialized or invalid value. Many compilers use special values to indicate uninitialized pointers in debug version.
This might also happen for 'dangling' pointers that have been already deleted earlier. This might well be the case, because in your destructor you are already deleting the next pointer:
~LinkedNode() {delete &next;}
Thus next will be invalid in the next iteration step in the clear() function. Even worse, the syntax you are using is valid, but semantically wrong here: You are trying to delete the address where the next pointer variable itself lives (that certainly never was allocated with new).
I'm creating something similar to structure list. At the beginning of main I declare a null pointer. Then I call insert() function a couple of times, passing reference to that pointer, to add new elements.
However, something seems to be wrong. I can't display the list's element, std::cout just breaks the program, even though it compiler without a warning.
#include <iostream>
struct node {
node *p, *left, *right;
int key;
};
void insert(node *&root, const int key)
{
node newElement = {};
newElement.key = key;
node *y = NULL;
std::cout << root->key; // this line
while(root)
{
if(key == root->key) exit(EXIT_FAILURE);
y = root;
root = (key < root->key) ? root->left : root->right;
}
newElement.p = y;
if(!y) root = &newElement;
else if(key < y->key) y->left = &newElement;
else y->right = &newElement;
}
int main()
{
node *root = NULL;
insert(root, 5);
std::cout << root->key; // works perfectly if I delete cout in insert()
insert(root, 2);
std::cout << root->key; // program breaks before this line
return 0;
}
As you can see, I create new structure element in insert function and save it inside the root pointer. In the first call, while loop isn't even initiated so it works, and I'm able to display root's element in the main function.
But in the second call, while loop already works, and I get the problem I described.
There's something wrong with root->key syntax because it doesn't work even if I place this in the first call.
What's wrong, and what's the reason?
Also, I've always seen inserting new list's elements through pointers like this:
node newElement = new node();
newElement->key = 5;
root->next = newElement;
Is this code equal to:
node newElement = {};
newElement.key = 5;
root->next = &newElement;
? It would be a bit cleaner, and there wouldn't be need to delete memory.
The problem is because you are passing a pointer to a local variable out of a function. Dereferencing such pointers is undefined behavior. You should allocate newElement with new.
This code
node newElement = {};
creates a local variable newElement. Once the function is over, the scope of newElement ends, and its memory gets destroyed. However, you are passing the pointer to that destroyed memory to outside the function. All references to that memory become invalid as soon as the function exits.
This code, on the other hand
node *newElement = new node(); // Don't forget the asterisk
allocates an object on free store. Such objects remain available until you delete them explicitly. That's why you can use them after the function creating them has exited. Of course since newElement is a pointer, you need to use -> to access its members.
The key thing you need to learn here is the difference between stack allocated objects and heap allocated objects. In your insert function your node newElement = {} is stack allocated, which means that its life time is determined by the enclosing scope. In this case that means that when the function exits your object is destroyed. That's not what you want. You want the root of your tree to stored in your node *root pointer. To do that you need to allocate memory from the heap. In C++ that is normally done with the new operator. That allows you to pass the pointer from one function to another without having its life time determined by the scope that it's in. This also means you need to be careful about managing the life time of heap allocated objects.
Well you have got one problem with your Also comment. The second may be cleaner but it is wrong. You have to new memory and delete it. Otherwise you end up with pointers to objects which no longer exist. That's exactly the problem that new solves.
Another problem
void insert(node *&root, const int key)
{
node newElement = {};
newElement.key = key;
node *y = NULL;
std::cout << root->key; // this line
On the first insert root is still NULL, so this code will crash the program.
It's already been explained that you would have to allocate objects dynamically (with new), however doing so is fraught with perils (memory leaks).
There are two (simple) solutions:
Have an ownership scheme.
Use an arena to put your nodes, and keep references to them.
1 Ownership scheme
In C and C++, there are two forms of obtaining memory where to store an object: automatic storage and dynamic storage. Automatic is what you use when you declare a variable within your function, for example, however such objects only live for the duration of the function (and thus you have issues when using them afterward because the memory is probably overwritten by something else). Therefore you often must use dynamic memory allocation.
The issue with dynamic memory allocation is that you have to explicitly give it back to the system, lest it leaks. In C this is pretty difficult and requires rigor. In C++ though it's made easier by the use of smart pointers. So let's use those!
struct Node {
Node(Node* p, int k): parent(p), key(k) {}
Node* parent;
std::unique_ptr<Node> left, right;
int key;
};
// Note: I added a *constructor* to the type to initialize `parent` and `key`
// without proper initialization they would have some garbage value.
Note the different declaration of parent and left ? A parent owns its children (unique_ptr) whereas a child just refers to its parent.
void insert(std::unique_ptr<Node>& root, const int key)
{
if (root.get() == nullptr) {
root.reset(new Node{nullptr, key});
return;
}
Node* parent = root.get();
Node* y = nullptr;
while(parent)
{
if(key == parent->key) exit(EXIT_FAILURE);
y = parent;
parent = (key < parent->key) ? parent->left.get() : parent->right.get();
}
if (key < y->key) { y->left.reset(new Node{y, key}); }
else { y->right.reset(new Node{y, key}); }
}
In case you don't know what unique_ptr is, the get() it just contains an object allocated with new and the get() method returns a pointer to that object. You can also reset its content (in which case it properly disposes of the object it already contained, if any).
I would note I am not too sure about your algorithm, but hey, it's yours :)
2 Arena
If this dealing with memory got your head all mushy, that's pretty normal at first, and that's why sometimes arenas might be easier to use. The idea of using an arena is pretty general; instead of bothering with memory ownership on a piece by piece basis you use "something" to hold onto the memory and then only manipulate references (or pointers) to the pieces. You just have to keep in mind that those references/pointers are only ever alive as long as the arena is.
struct Node {
Node(): parent(nullptr), left(nullptr), right(nullptr), key(0) {}
Node* parent;
Node* left;
Node* right;
int key;
};
void insert(std::list<Node>& arena, Node *&root, const int key)
{
arena.push_back(Node{}); // add a new node
Node& newElement = arena.back(); // get a reference to it.
newElement.key = key;
Node *y = NULL;
while(root)
{
if(key == root->key) exit(EXIT_FAILURE);
y = root;
root = (key < root->key) ? root->left : root->right;
}
newElement.p = y;
if(!y) root = &newElement;
else if(key < y->key) y->left = &newElement;
else y->right = &newElement;
}
Just remember two things:
as soon as your arena dies, all your references/pointers are pointing into the ether, and bad things happen should you try to use them
if you ever only push things into the arena, it'll grow until it consumes all available memory and your program crashes; at some point you need cleanup!
I am working on some binary tree algorithms and need a "find node with searchindex..." function. The design for treenodes is basically
class TreeNode {
int index; // some identifier
TreeNode *left;
TreeNode *right;
}
and a tree is defined by a pointer to the root-node.
My implementation for the search function is:
void Tree::searchNode(TreeNode * root, int nodeIndex, TreeNode *resultNode){
/* Recursive search */
if (root->index == nodeIndex) {
resultNode = root;
} else {
/* search children if the current node is not a leaf */
if(!root->isLeaf()) {
this->searchNode(root->left,nodeIndex,resultNode);
this->searchNode(root->right,nodeIndex,resultNode);
}
}
}
Arguments: *root is the root-node of the tree, nodeIndex is the search-index and *resultNode is the pointer to the found (or not) node in the tree.
The function does not return a reference or pointer to the found node but modifies the pointer resultNode so it points to the found node. The idea is to initialize resultNode with NULL, perform the search and modify it if a match occurs. Otherwise it remains NULL and I can easily check if there are search results or not.
Another class with a tree buildingTree as member utilizes the search-function in this way:
TreeNode *resultNodePtr = NULL;
this->buildingTree->searchNode(this->buildingTree->rootPtr,
currentNodeIndex, resultNodePtr);
// do sth. with resultNodePtr if != NULL
I create *resultNodePtr on the stack because I just need it temporarily inside the function. Is this done correctly? However: The function does not work. resultNodePtr is always NULL, even if the tree contains a node with the search-index. I debugged it very carefully step by step, it detects
(root->index == nodeIndex)
correctly but
resultNode = root;
does not work (I want resultNode to point to the same adress root points to).
Debugger says resultNode before assignment is 0x0, root node is some adress, after the assignment resultNode remains 0x0.
Do I have to overload the operator= in this case for the class TreeNode?
I have tried it:
TreeNode & TreeNode::operator=(const TreeNode & oldTreeNode){
*this = oldTreeNode;
return *this;
// ignore childs for now
}
I am not an expert but this operator= seems trivial. Does it affect the assignment of two TreeNode pointers *node1 = *node2 at all?
Maybe you can help me. Thanks for reading, appreciate your help.
If I find a solution myself I will post it here.
Regards,
Mark
Because you pass resultNode into the function as a pointer by value, its original value never changes. Think of TreeNode* as literally nothing more than a number representing a memory address; when you reassign it:
resultNode = root;
This modifies the copy that searchNode has, but not the original pointer in the code which invokes searchNode. Take this simpler example:
void Foo(int x)
{
x = 100;
}
void Bar()
{
int x = 0;
Foo(x);
// at this point, x is still 0
}
resultNode's value doesn't change from NULL for the same reason that x doesn't change from 0 when the function Bar is invoked. To fix this issue, pass the pointer in as a pointer to a pointer, or a pointer by reference:
void Tree::searchNode(TreeNode* root, int nodeIndex, TreeNode*& resultNode)
{
// same code
}
... or:
void Tree::searchNode(TreeNode* root, int nodeIndex, TreeNode** resultNodePtr)
{
// assign to *resultNodePtr instead
}
Your resultNode pointer is being passed by value, not by reference. So when the function call completes the pointer on the calling side does not receive a value.
Your algorithm looks fine :)