My C++ program crashes on this function? - c++

I'm a beginner programmer(Just started) and I'm writing some code for a binary search tree for fun.
For some reason, whenever I call this append function my program crashes. It has to do with one of the two functions itself, not anything else in the header file or my source file which includes main(). By the way Leaf is just a struct with an int value, and two Leaf pointers named left and right.
This crashes with no output error.
Leaf* BinarySearchTree::GetLeaf(int x,Leaf*a)
{
int key = a->value;
cout <<key<<"\n";
if(x > key)
{
if(a->right == NULL)
{
Leaf* newleaf = new Leaf();
newleaf->value = x;
a->right = newleaf;
return newleaf;
}
else if (a->right != NULL)
{
return a->right;
}
}
else if(x< key)
{
if(a->left == NULL)
{
Leaf* newleaf = new Leaf();
newleaf->value = x;
a->left = newleaf;
return newleaf;
}
else if (a->left != NULL)
{
return a->left;
}
}
else if(x == key)
{
//tbc
}
}
void BinarySearchTree::Append(int x)
{
if(root != NULL)
{
Leaf* current = root;
while(current->value != x)
{
current = BinarySearchTree::GetLeaf(x,current);
cout<<"value: "<<
current->value;
}
}
else
{
cout <<" No ROOT!";return;
}
}
If you want to see my main (source) file, go here(Since I don't want to flood this post)
http://pastebin.com/vrh7KkMm
If you want to see the rest of the header file, where these two functions are located,
http://pastebin.com/ZGWewPdV

In your BinarySearchTree constuctor, you start accessing root without having allocated memory for it first. This may be your crash. Try adding
root = new Leaf()
at the start of the constructor.
Edit - More information:
C++ does not automatically set values for your member variables, you normally need to initialize them by hand. (c++11 does allow you to do it in the declaration). This means that any variable that you don't set to a value will have a garbage value in it. If you use this garbage value as a pointer, you will most likely get a crash.
In your case, one of the initial problems is that the LinkedList class did not initialize its root member variable in the constructor before starting to reference it.
BinarySearchTree has the same problem.
Learning to use the debugger is one of the best things you can do when learning to program. It lets you step through your code one line at a time and look at the value of each variable. This makes i easy to see where things aren't going as you planned. Which debugger you use depends on your platform.

If GetLeaf() is called with x == key the function returns neither nullptr nor a valid pointer. This is a potential crash source. You need to return something sensible in any case.
UPDATE: Don't forget to initialize the Leaf structure properly in its constructor (all three members).
UPDATE2: Also initialize your root properly. I would initialize it with nullptr and change the append function in a way that it creates the very first leave if root==nullptr.

Related

Declaring any new variable changes pointer address for unknown reason

I am writing an auction program for a class project and one of the features I was trying to implement was a hash table to make searching for auction items by name efficient. I set it up in node format so that you can chain nodes together if their hash value lines up with another item that already exists.
The main problem that I cannot seem to figure out is how some pointer values are changing when I don't think I have done anything to them. I stepped through each line of this program keeping an eye on the Red highlighted areas in the attached screenshots to see when the data changes. In case #1 the data was intact and able to be accessed. However, in case #2 where I simply declare an additional variable (int i = 0;) suddenly the data passed into the function appears to point to a different memory location (0xcccccccc) which from what I understand is another version of null? This is the same no matter what variable type I have tried to declare whether it be an int, const char*, string, etc it all reacts like the second screenshot.
Does anyone know why the program would be doing this? Are there any other troubleshooting tips? Is this a common error and how should I avoid it in the future and for this project?
I can provide a complete code if needed. I appreciate any help you can provide.
Image 1: No additional variable declared, data in tact as expected
Image 2: integer variable declared, data at ->next suddenly changed. This appears to be this way from the start of the function.
Update: I created an MRE as suggested in a comment, the same error can be reproduced using this code.
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
class AuctionItemBidsMaxHeap {
string name = "test";
public:
const char * getItemName() {
return name.c_str();
}
};
class AuctionItemHashTable {
private:
struct Node {
AuctionItemBidsMaxHeap* AuctionItem;
Node* next = nullptr;
};
Node* itemArray;
int capacity = 50;
int generateHashKey(string auctionItem) {
return 11;
}
public:
AuctionItemHashTable() {
//Create the array of X amount of different possible storage locations
Node emptyNode;
emptyNode.AuctionItem = nullptr;
emptyNode.next = nullptr;
itemArray = new Node[capacity];
for (int i = 0; i < capacity; i++) {
itemArray[i] = emptyNode;
}
}
~AuctionItemHashTable() {
delete itemArray;
}
void insertItem(AuctionItemBidsMaxHeap* auctionItem) {
//Check to see if this item already exists
int key = generateHashKey(auctionItem->getItemName());
Node newAuctionItem;
newAuctionItem.AuctionItem = auctionItem;
newAuctionItem.next = nullptr;
//Check to see if anything has been inserted there yet
if (itemArray[key].AuctionItem == nullptr) {
itemArray[key] = newAuctionItem;
}
else {
//WE have to make room in the semi-linked list
Node holder;
holder.AuctionItem = itemArray[key].AuctionItem;
holder.next = itemArray[key].next;
newAuctionItem.next = &holder;
itemArray[key] = newAuctionItem;
}
}
AuctionItemBidsMaxHeap* getAuctionItem(const char* itemName) {
int key = generateHashKey(itemName);
//Loop through all items in location
Node* currentNode = &itemArray[key];
if (currentNode == nullptr) {
return nullptr;
}
else {
if (currentNode->AuctionItem->getItemName() == itemName) {
cout << "Match" << endl;
}
while (currentNode->next != nullptr && currentNode->next != (void*)0xcccccccc) {
int i = 0;
if (currentNode->next->AuctionItem->getItemName()[0] == 'M') {
cout << "M Matched" << endl;
}
while (currentNode->next->AuctionItem->getItemName()[0] != 'e') {
//cout << currentNode->next->AuctionItem->getItemName()[i];
}
currentNode = currentNode->next;
}
//There was an item stored at this location, lets see which one it is
//void* p = (void*)0xcccccccc; //Creating a pointer since for some reason my final pointer gets changed to another type of null character upon passing it to a function
//cout << currentNode->AuctionItem->getItemName() << endl;
//while (currentNode->next != nullptr && currentNode->next != p) {
//cout << currentNode->AuctionItem->getItemName() << endl;
//currentNode = currentNode->next;
//}
return currentNode->AuctionItem;
}
}
};
int main()
{
/**Creating MaxHeap of one bid**/
AuctionItemBidsMaxHeap myBidTest;
AuctionItemBidsMaxHeap myBidTest2;
/**Creating Auction Item Hash Table**/
AuctionItemHashTable auctionItems;
auctionItems.insertItem(&myBidTest);
auctionItems.insertItem(&myBidTest2);
const char* myInput = "test";
auctionItems.getAuctionItem(myInput);
}
First a rant: Why is it that classes still teach pointers in C++? There are MUCH better ways to do this than Node*.
Your code contains several errors, but the most important one is here:
//WE have to make room in the semi-linked list
Node holder;
holder.AuctionItem = itemArray[key].AuctionItem;
holder.next = itemArray[key].next;
newAuctionItem.next = &holder; ////<<< ERROR HERE
itemArray[key] = newAuctionItem;
You create a temporary variable on the stack Node holder; This variable will be destroyed as soon as you leave the function.
But you take a pointer to this variable here
newAuctionItem.next = &holder;
IOW: Your list contains pointers to objects that no longer exist.
&holder is the address of the variable holder. As soon as holder goes out of scope, the contents of it will be destroyed. But newAuctionItem.next and as a consequence also itemArray[key].next will still point to the memory, where holder used to be.
This is what is called a dangling pointer.
I stopped reading your example, but it is also pretty dangerous to accept pointers to AuctionItems in your insert method. When you are using pointers here, you MUST MAKE SURE, that the actual objects remain valid for as long as they are in the list.
Or, to put it the other way round: You must remove them from your list before they get destructed. And we humans are not made to "make sure". We make errors, so it is better to write code where you cannot make an error like this (i.e. avoid pointers in the first place).
Another error: You are creating an array with itemArray = new Node[capacity];, but you are deleting it with delete itemArray;. When you are using new to create an array, you must use delete[] itemArray to delete it. See here delete vs delete[] operators in C++
A general note: DO NOT USE POINTERS AT ALL (unless you have to). Pointers are an advanced C++ concept.
You could use shared_ptr<> instead. This will take away the burdon of freeing the memory.
For your itemArray you could use std::vector<> instead of allocating an array with new[]; etc...
There are many good and easy to use classes in the C++ library, which will help you a lot writing safer and cleaner code.
Learning C++ is (at least) as much about learning the std Library as about learning the syntax and statements. std::vector<AuctionItemNodes> IS C++.

intersection function gets stuck after output

void intersectionLists(LinkedList argList) {
bool common = false;
ListNode* thisCurrentPointer{headPointer};
ListNode* argCurrentPointer;
cout <<"common elements between both lists are:\n";
while(thisCurrentPointer != nullptr) {
argCurrentPointer = argList.getHeadReference();
while(argCurrentPointer != nullptr){
if(thisCurrentPointer->data == argCurrentPointer->data) {
cout <<thisCurrentPointer->data;
common = true;
break;
}
argCurrentPointer = argCurrentPointer->nextPointer;
}
thisCurrentPointer = thisCurrentPointer->nextPointer;
}
if(!common) {
cout <<"none\n";
}
thisCurrentPointer = nullptr;
argCurrentPointer = nullptr;
delete thisCurrentPointer;
delete argCurrentPointer;
}
Hello everyone,
Iwas making this function for intersection in the linkedList class, which has the parameter of another linkedList object, one utility function i am using on line 9 is getHeadReference(), which simply returns the address stored in the headPointer (i am using this function in order to get argCurrentPointer to point at the head of the list that came in the parameter).
Anyway.. the function gives perfectly fine output of whatever two linked lists are but the control get "stuck" right after its execution, the control freezes, and a huge garbage value is returned, i really hope i am being clear.
I have dry run the code i can not seem to find the problem. Even in main when i call another function after the execution of "intersectionLists" function, the called function gets executed properly without any delay but the control can't seem to exit main after all the work is done, when i don't call this intersection code, no hang or delay whatsoever is observed, please help. Thank you.
I think this is because you detele thisCurrentPointer and argCurrentPointer after setting them to null. It is not necessary to do any deletion after as you are not duplicating your nodes.

Defining an object inside a function in a B+ tree

I am trying to implement a B+ tree. This is a very small portion of the actual code. I had some problems when passing an object pointer to a function. As far as I know, those objects created inside the function are destroyed afterwards. So what would be a good way to improve this without changing the semantics and still keep the function recursive. Any feedback would be appreciated.
void percolate_up(IndexNode* Current, int btree_order, IndexNode* Right, IndexNode* Root)
{
if(Current->Parent == NULL)
{
IndexNode* UpperNode = new IndexNode;
UpperNode->AddChild(Current);
UpperNode->AddChild(Right);
Current->Parent = UpperNode;
Right->Parent = UpperNode; //This is defined inside an if statement
// in main yet this statement doesn't affect it
UpperNode->AddKey(Current->Keys[btree_order]);
Root = UpperNode;
}
else if(.......){
...
...
percolate_up(....);
}
}
int main(){
...
if(...){
IndexNode* RightNode = new IndexNode;
percolate_up(Current, btree_order, RightNode, Root);
//RightNode->Parent is still NULL here but Current->Parent is changed
//Also Root is unchanged, Why does this happen?
}
All objects created with "new" will exists after function return. So you should use it.

recursively delete every nodes in binary tree

Following is my code to recursively delete every nodes in a Binary Search Tree:
template <class T>
bool BST<T>::clear()
{
if(root == NULL)
{
cout << "Empty" << endl;
return false;
}
else
{
clearNodes(root);
return true;
}
}
template <class T>
void BST<T>::clearNodes(BTNode<T> *cur)
{
if(cur == NULL)
{
return;
}
clearNodes(cur->left);
clearNodes(cur->right);
delete cur;
}
In my main function, when I try to print out the content to check whether the nodes are deleted after running my clear function, somehow I encounter the weird display here:
May I know that is my nodes are actually deleted through the clear function above?
Thanks for your guides!
I assume "checking that the nodes are deleted" is equivalent to clear() printing empty. Your algorithm is missing the step where it reset the deleted node.
A modified version is
template <class T>
void BST<T>::clearNodes(BTNode<T>* &cur) //reference on pointer
{
if (cur==NULL)
{
return;
}
clearNodes(cur->left);
clearNodes(cur->right);
delete cur;
cur = NULL; //neccessary
}
Edit : Explanation about changes
Once you observe the issue about the node not set to null, the first iteration will be to set the node in question after every call, ie
clearNodes(cur->right);
cur->right = NULL;
This give the responsibility to the caller, and his a potential defect because sooner or later the caller may forget to set to null or may set the wrong value. Thus you want to set in clearNodes.In order to modify a pointer inside the function you need to pass either a pointer to it or a reference. In c++, I prefer to pass a reference. Thus the signature become¨
void BST<T>::clearNodes(BTNode<T>* &cur);
I guess that the root of the tree is not set to Null, therefor it holds garbage, and the print function is iterating a random-garbage tree.
Make sure you set NULL to the tree root when the clear method ends.
template <class T>
bool BST<T>::clear()
{
if (root==NULL)
{
cout << "Empty" << endl;
return false;
}
else
{
clearNodes(root);
root = NULL;
return true;
}
}
I assume that when you print - you check if the tree root is null or not in order to determine whether the tree is empty or not.

Question about linked lists/pointers in c++

The nature of pointers being NULL in C++ seems to feel arbitrary. I'm sure there's a method to it that I'm missing, but the following makes sense to me, but doesn't seem to work. I have the following method for adding a node to a linked list:
LLNode *ll; // set to NULL in constructor.
void addToLL(Elem *e)
{
LLNode *current = ll;
while(true)
{
// edge case of an empty list.
if (ll == NULL)
{
ll = new LLNode(e);
break;
}
else if (current == NULL)
{
current = new LLNode(e);
break;
}
else {
current = current->next;
}
}
}
When adding a 2nd node to the list, the case for current == NULL does not get caught, so it tries to call current = current->next and crashes do to accessing invalid memory. Why would this be the case? A LLNode has a pointer to an Elem, and a pointer called next to another LLNode.
You probably didn't set the next pointer to NULL in the LLNode constructor.
Objects of the basic types in C++ (pointer types, numeric types, etc.) have indeterminate initial values: they don't get initialized by default. You need to explicitly initialize such objects before you use them.
For this sort of thing you need a pointer to a pointer in order to strip away a lot of the needless exceptions in your implementation:
LLNode *ll = NULL;
void addToLL(Elem *e)
{
LLNode** current = &ll;
// While the current pointer to pointer is mapped to something,
// step through the linked list.
while (*current)
current = &(*current->next);
// At this point current is pointing to a NULL pointer and can
// be assigned to.
*current = new LLNode(e);
}
The reason pointers are NULL is because that evaluates to false and allows you to do simple checks such as while (*current) without a lot of overhead. In the CPU this usually ends up being implemented as a test-if-zero operation.
Pointers are only NULL if initialized as such. In C they are often undefined unless properly initialized and referencing an uninitialized pointer is recipe for disaster. You'll want to ensure any pointers you define are always initialized to something valid before using them.
1) You say that ll is set to NULL in the constructor. But what constructor? There's no class definition here. Is ll a global variable? And are you sure that the constructor for LLNode sets the next pointer to NULL?
2) The condition
if (ll == NULL)
can and should be checked outside of the loop, as ll is not modified inside the loop.
3) current is a local stack variable, so assigning to it will have no effect once the function exits. In particular, current = new LLNode(e) is a memory leak.
4) To add a node to the linked list, you must find the last node of the existing list, and modify its next pointer. Something like this would work:
// ll is a field representing the first node in your existing linked list.
if (ll == NULL) {
ll = new LLNode(e);
}
else {
current = ll;
while (current->next != NULL) {
current = current->next;
}
current->next = new LLNode(e);
}
EDIT: Modified the above based on your comment that ll is a class member.
The first thing I see in your code is that current is local, gets allocated with new but is never actually attached to the list.
Surely your code should be
else if( current->next == NULL )
{
current->next = new LLNode( e );
break;
}
LLNode must of course initialise next to NULL in its constructor.
Of course your list has O(N) insertion time, and if this is anything other than an exercise you should be almost certainly be using standard library containers.
You should also probably move the edge case out of the loop.