I want to read binary tree from file. I have written a method.
BinaryTree * FileService::read(BinaryTree * node) {
basic_string<char> np = "nullptr";
char * val = new char ();
if (!fscanf(this->filePtr, "%s ", val)) {
delete val;
return node;
}
string str(val);
if (str == np) {
delete val;
return node;
}
node = new BinaryTree();
if (Helper::isFloatNumber(val)) {
node->setNumericValue(stof(val));
} else {
node->setStrValue(val);
}
delete val; <----HERE SIGTRAP (Trace/breakpoint trap)
node->setLeft(this->read(&node->getLeftReference()));
node->setRight(this->read(&node->getRightReference()));
return node;
When I execute my code, I get an error Process finished with exit code -1073740940 (0xC0000374) When I try to debug I receive this one SIGTRAP (Trace/breakpoint trap) where last delete val is. When I comment this line my code works well. But I think memory leak will be there in this case. Tell me please where am I wrong? And how can I change my code to avoid memory leak and exceptions?
I tried to move line delete val; before last return. It didn't fix. I tried to make condition
if (val != nullptr) {
delete val;
val = nullptr;
}
instead every delete val; result was the same.
Related
I am learning about reference pointers and memory leaks.
I have created a method that takes in a pointer to a NodeData, create a Node that contains NodeData, and a left pointer, and a right pointer, and insert it depending on its value. I am using a reference pointer to traverse my tree. I am getting a memory leak every time I declare a new Node object and go outside of the scope.
I thought that since the pointer reference is pointing to the object, it has not disappeared. My program runs fine, but when I use valgrind it comes up with an error.
I have written this method multiple ways but cannot find out a way to fix it. I have posted the most concise method I've written.
bool BinTree::insert(NodeData* s) {
Node* currentPtr = root;
bool insert = insertHelper(s, currentPtr);
return insert;
};
bool BinTree::insertHelper(NodeData* s, Node*& currentPtr) {
if (currentPtr == NULL) {
Node* newNodePtr = new Node;
newNodePtr->data = s;
newNodePtr->left = NULL;
newNodePtr->right = NULL;
currentPtr = newNodePtr;
return true;
} else if (*s == *currentPtr->data) {
return false;
} else if (*s < (*currentPtr->data)) {
return insertHelper(s, currentPtr->left);
} else {
return insertHelper(s, currentPtr->right);
}
}
I'm getting a lot of memory leaks throughout my program due to similar errors.
Or, would anyone explain the concept behind the pointer reference, or ways to learn more about it?
The method is used by this method:
void buildTree(BinTree& T, ifstream& infile) {
string s;
for (;;) {
infile >> s;
cout << s << ' ';
if (s == "$$") break; // at end of one line
if (infile.eof()) break; // no more lines of data
NodeData* ptr = new NodeData(s); // NodeData constructor takes string
// would do a setData if there were more than a string
bool success = T.insert(ptr);
if (!success)
delete ptr; // duplicate case, not inserted
}
}
You might have a bit more luck with this
bool BinTree::insert(NodeData* s) {
bool insert = insertHelper(s, root);
return insert;
};
Your code modified a local variable, not the root.
If you want to modify the root, you need a reference to the root, not to a local variable which has a copy of the root.
I am trying to find the node where the cycle begins in the list. The result returned is correct. However, an error stating * Error in ./solution: double free or corruption (fasttop): 0x0000000000b3e030
Aborted is shown. I saw some other similar problems, and I think the problem is with temp1=temp;. But I don't know how to solve this problem.
How to correct it? Also why is this error occurring?
ListNode* Solution::detectCycle(ListNode* A) {
ListNode* temp = A;
ListNode* temp1 = A;
while(temp->next!=NULL && temp->next->next!=A->next ){
temp1 = temp;
temp = temp->next;
temp1->next=A->next;
}
if(temp->next==NULL) {
temp->val=-1;
delete temp1;
return temp;
}
else {
temp= temp->next;
delete temp1;
return temp;
}
}
Thank you.
As a direct answer, your code is crashing because your are accessing nodes that are already free. Beyond accessing, you are deleting a node that has already been deleted. This 'double free' will almost alway result in a crash or other chaos. A strong understanding of heap mechanics in C/C++ will save you a lot of misery, it is worth studying.
I'm not too sure what the requirements are but I believe your are trying to check for a circular linked list. I not clear why you are deleting any of the nodes in a 'detect' method. Are you trying to break the loop? If so, all of the node will still be in the list so nothing will be deleted, just change the ->next to nullptr on the node that loops back.
Here is some example code from your original. I created it using your code as a base and then using the gdb debugger to debug it. An effective software engineer is a master of the debugger, embrace it. It is a Minimal, Complete and Verifiable example as described in the comments.
I put a few tests as an example of 'use cases', no loop, degenerate loop, longer loop. As software engineers, a big part of our job is thinking about error cases which often occur on the boundaries. There may be others that I have not covered.
As noted in the comments, compiling or a single successful use case doesn't indicate defect free software. Rigorous testing is needed to gain confidence. This kind of testing is often referred to as 'unit testing' there is a large body of literature on the subject.
#include <iostream>
struct ListNode
{
int val;
ListNode* next;
};
//Look for a loop back to A
ListNode* detectCycle(ListNode* A) {
if(A == nullptr) // can't be a loop if list is empty
return nullptr;
ListNode* temp = A;
while(temp->next!=NULL && temp->next !=A ){
temp = temp->next;
}
if(temp->next==NULL) {
return nullptr; // No loop
}
else {
return temp; // Node where loop starts, may be A itself
}
}
int main(int argc,char* arv[])
{
ListNode *a = new ListNode;
ListNode *loop = nullptr;
loop = detectCycle(a);
if(loop == nullptr)
std::cout << "Case 1 passed" << std::endl;
a->next = a;
loop = detectCycle(a);
if(loop == a)
std::cout << "Case 2 passed" << std::endl;
ListNode *b = new ListNode;
ListNode *c = new ListNode;
ListNode *d = new ListNode;
a->next = b;
b->next = c;
c->next = d;
d->next = a;
loop = detectCycle(a);
if(loop == d)
std::cout << "Case 3 passed" << std::endl;
loop = detectCycle(b);
if(loop == a)
std::cout << "Case 4 passed" << std::endl;
return 0;
}
I'm trying to implement a binary search tree in C, more specifically looking for the predecessor. However, whenever I try to run the program I get the segmentation vault. Here's the code in question:
#include <stdio.h>
#include <stdlib.h>
struct tree
{
int a;
tree *left;
tree *right;
tree *prev;
}*root=NULL;
tree *searchSpecific (tree *root, int val)
{
tree *x=root;
if (!x)
{
return NULL;
}
else
{
while(x && val!=x->a)
{
if (val>x->a)
x=x->left;
else x=x->right;
}
}
return x;
}
int previous(tree *root, int f)
{
tree *x=searchSpecific(root,f);
if(x->left)
{
x=x->left;
while(x->right) x = x->right;
return x->a;
}
tree *temp;
do
{
temp = x;
x = x->prev;
} while(x && (x->right != temp));
return x->a;
}
The segfault appears at the if statement if(x->left) in the previous() function. I want to check if the node in question exists, but the program crashes every time and I have no idea what is wrong with it..
Since searchSpecific may return NULL, you need to protect your code from it, and check x before accessing one of its members:
tree *x=searchSpecific(root,f);
if (x != NULL && x->left)
The segmentation fault can appear due to several reasons, such as:
x is undefined, which may be caused by your *searchSpecific function
x is NULL, because your function returns a NULL pointer
x->left is NULL, which means trying to access it causes something bad to happen
So, how I'll go about doing this would be trying to check if the returned tree is null using a simple if statement as follows:
if (x == NULL) {
/* throw error or not found message */
}
I would also suggest you dynamically allocate memory for your tree before doing anything with it, by creating a reusable func like create_tree() with the following code:
tree create_tree(int data) {
tree *x;
x = malloc(sizeof(tree));
x->a = data;
x->left = x->right = x->prev = NULL;
return x;
}
Why? Note that in your code snippets, you just declare
tree *some_tree_name;
which is very dangerous every time you try to do something with it, and might lead to your code crashing on you on the do/while loop later.
So I have a linked list program semi working. I am just having some trouble with certain methods.... The ones I have documented bekiw are working except for delete from end which is acting weird.
I am using NetBeans on Mavericks with G++ as my compiler and C++11
Here is a zip of all of the program files
Here is a list of the methods I am trying to make:
//working
int size() const;
/kind of
void addToStart(Node *);
//working
void addToEnd(Node *);
//working
void printList();
//working
bool removeFromStart();
//kind of working
bool removeFromEnd();
//Still working on these
void removeNodeFromList(int);
void removeNodeFromList(string);
For now, I have to run removeFromEnd() twice in order for it to work. Meaning, I run it once at the beginning of the program and it does nothing, but every subsequent time, it actually does the deleting.
For addToStart() it works if I only run it once. I.E:
I can run it once at the beginning of the program and print out the list
I can run it once AFTER using addToEnd, but if I try it a second time, and I try to print out the list, it just keeps spitting out the value I tried to add.
addToEnd() works perfectly find if I just keep running that, but it fails if I:
Start out by using addToEnd() to add items, then use addToStart() ONCE and THEN try to use addToEnd() again. When I print out the list, it only prints out two objects and each of those is a copy of the last value I tried to insert.
void LinkedList::addToEnd(Node* ne)
{
Node** q = &myHead;
while (*q)
{
q = &(*q)->next;
}
*q = new Node(ne->itemName, ne->itemNo);
}
void LinkedList::printList()
{
Node* p = myHead;
while (p != NULL)
{
cout << p->itemNo << " " << p->itemName;
cout << endl;
p = p->next;
}
cout << endl << endl;
}
bool LinkedList::removeFromStart()
{
if (myHead == NULL)
{
cout << "List is already empty";
}
else
{
myHead = myHead->next;
}
}
bool LinkedList::removeFromEnd()
{
if (myHead == NULL)
return false;
//Empty the list if there's only one element
if (myHead->next == NULL)
{
delete myHead;
myHead = NULL;
myTail = NULL;
return true;
}
// Find the last item in the list
Node *temp = myHead;
while (temp->next != myTail)
{
temp = temp->next;
}
delete myTail;
temp->next = NULL;
myTail = temp;
return true;
}
Also, still trying to figure out the remove ones
void LinkedList::removeNodeFromList(int i) {
//Save the values
Node* p = myHead;
Node* temp = myHead->next;
while (p) {
if (p->itemNo == i) {
p=temp;
} else {
p = p->next;
}
}
}
You have a tail pointer, so why are you iterating through the list to find the end? Additionally, why are you passing the node by pointer?
void LinkedList::addToEnd(Node ne)
{
if (myHead == nullptr) // empty list
{
myHead = myTail = new Node(ne);
myTail->next = nullptr;
}
else
{
myTail->next = new Node(ne); // assuming Node has an accessible copy constructor
myTail = myTail->next;
}
}
The removeFromStart function has a memory leak:
bool LinkedList::removeFromStart()
{
if (myHead == nullptr)
{
cout << "List is already empty";
return false;
}
Node* temp = myHead;
myHead = myHead->next;
if (myTail == temp) // if there is only 1 element in the list, head == tail
{
myTail = myhead;
}
delete temp;
return true;
}
Presumably, removeFromEnd should be removing the tail:
bool LinkedList::removeFromEnd()
{
if (myTail == nullptr)
return false;
// unless you have a doubly-linked list, loop to find 1 before the tail
Node* temp = nullptr;
for (temp = myHead; temp && temp->next != myTail; temp = temp->next);
if (myHead == temp) // when there is only 1 element in the list, head == tail
{
delete temp->next;
myHead = nullptr;
myTail = nullptr;
}
else
{
delete temp->next;
temp->next = nullptr;
myTail = temp;
}
return true;
}
And yes, you are using new (in your addtoEnd function), so you must use delete (not free!).
Side note: You can write the remove code better by using std::unique_ptr (you can actually improve the code overall by using it everywhere) which will make your code for each about 4 lines long. I'll leave that for you to implement.
You have a member called myTail that you seem to be using 'sometimes'
In addFromEnd you do not update myTail.
In one of the remove functions you do not update myTail even though you might change it
But in RemoveFromTail you are trying to use it.
There is no reason that myTail will contain a valid value and when you try to use it you can get an error (cause the node may have been deleted) or an unexpected result because it just points somewhere in the list.
You should either lose it (since you can easily figure out the tail. it is the node where next==NULL) or take care to maintain it in every call that changes the List (only if the tail is affected obviously)
Since you are using c++11 a few suggestions:
use nullptr instead of NULL
use std::unique_ptr for Next. It will take care of 'deleting' nodes you are no longer using for you.
use a copy ctor for Node. If you ever make a change to Node you will not need to revisit this part of the code just the constructors.
If you are holding copies of objects in the list. Then it is much clearer if your interface will accept const Node& instead of Node*. To me Node* makes it seem like you are going to use the ptr the user supplied.
Does this look right? I mean I am trying to implement the delete function.
Node* BST::findNode(int tofind) {
Node* node = new Node;
node = root;
while (node != NULL) {
if (node->val == tofind) {
return node;
} else if (tofind < node->val) {
node = node->left;
} else {
node = node->right;
}
}
}
Here is the delete, it's not even close to done but,
void BST::Delete(int todelete) {
// bool found = false;
Node* toDelete = new Node();
toDelete=findNode(todelete);
if(toDelete->val!=NULL) {
cout << toDelete->val << endl;
}
}
This causes a segmentation fault just running that, any ideas?
The main problem with findNode() is that you never return the node that you've found. That's why you're getting the segfault.
Also, in deleteNode() you should check whether findNode() has returned NULL. And of course you also need to code up the rest of the deletion logic.
Finally, the two new Node allocations are unnecessary and are leaking memory.
oh wait it's because in delete I should have done:
if(toDelete!=NULL) {
cout << toDelete->val << endl;
}
before it was
if(toDelete->val!=NULL)