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 = ≪
// 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.
Related
I've pinpointed my issue to this specific function, it's the helper function for my binary tree. Before this function call there is a node but instead of growing it seemingly just replaces that node. When I look at my code in my head it all makes sense but I can't figure out what I'm doing wrong.
Here is the function that calls add:
void BSTree::Insert(Client &newClient) {
if (isEmpty())
{
Node *newNode = new Node(newClient);
this->root = newNode;
}
else
add(this->root, newClient);
}
and here is my add() function:
BSTree::Node* BSTree::add(Node *node, Client &newClient) // helper function for Insert()
{
if (node == nullptr)
{
Node *newNode = new Node(newClient);
//node = newNode; // already tried adding this in
return newNode;
}
if (newClient.clientID < node->pClient->clientID)
return node->left = add(node->left, newClient); // already tried just returning add()
else
return node->right = add(node->right, newClient);
}
Since this is your question, I will explain what your code is doing. Imagine you have a mature binary tree already and you are adding a node to your tree. By the time you reach this line
return node->left = add(node->left, newClient);
Three separate instructions are carried out:
newClient is added to the left branch of node by add().
the left child of node is set to the return value of add().
the right hand side (RHS) of the assignment is returned by the parent function.
The issue is with number 2. If the tree you are adding to is mature already, changing left child of nodes as you're traversing the tree will cause the override effect that you're observing. In fact, the problem goes beyond overwriting leaves. Since you use the new keyword, the overwritten nodes still have allocated heap space, are never deleted and cause a memory leak.
Here are some thoughts to get you on the right direction:
Your insert() function ensures that the first time you call add(), you are not passing nullptr as the first argument. Take advantage of that and ensure nullptr is never passed into add() function by checking for nullptr before you do the recursive call. Change the return type of add() to void. You no longer need to check node is nullptr. Here's some pseudocode to guide you
void add(node, val)
if val < node.val
if node.left exists
add(node.left, val)
else
make a new object and set node.left to that object
else
if node.right exists
add(node.right, val)
else
make a new object and set node.right to that object
There is a problem with your logic. First of all, there is the insert() method which you should write like this for better understanding:
void BSTree::Insert(const Client &newClient) // use const to prevent modification
{
if (isEmpty()) { root = new Node(newClient); }
else { add(this->root, newClient); }
}
This way you are creating a new object at root directly with the help of 'root' pointer in BSTree.
Now, about the add() method. The 'node' you are passing as a parameter is a copy of the pointer variable, so the actual pointer value is not changed. See this:
BSTree::Node* BSTree::add(Node *node, Client &newClient) //logical error
You need to pass the Node* by reference like this using 'Node* &node':
BSTree::Node* BSTree::add(Node* &node, const Client &newClient)
Why is you binary tree overwriting the roots of its leaves? Answer:
Your recursive call with return statement is totally wrong.
return node->left = add(node->left, newClient);
The add(node->left, newClient) always returns the address of the leaves, and you are returning this value. It goes for recursive calls until it reaches the leaves place.
Conclusion: Since, there are a lot of bugs, I would suggest you re-write logic again carefully.
I hope this helps! :-)
I'm having a problem in a function that deletes an element in a singly linked list. The element needs to be deleted conditionnaly with the function ShouldDelete().
I haven't found a similar request in C++ in the forums so any help would be appreciated. It seems that the following code does not work 100% of the time.
void SinglyLinkedList::DeleteObjects(Node *pStartPtr)
{
Node *pPtr = pStartPtr;
Node *temp;
while(pPtr != nullptr)
{
temp = pPtr->next;
if (pPtr->ShouldDelete())
{
delete pPtr;
pPtr = temp;
if(temp != nullptr)
{
pPtr->next = temp->next;
}
}
pPtr = temp;
}
}
Any thoughts ?
Thanks!
As a general C++ advice, I would use std::list instead of a DIY list implementation, but since I wrote quite some list logic myself in the old C-days, I'll give it a go.
There are 2 essential problems with your code.
First of all, whenever removing an element from a single-linked list, you should set the next pointer of the previous element to the next of the deleted one. You can do something like this:
Node *previousNode = …;
while(pPtr != nullptr)
{
Node *nextNode = pPtr->next;
if (pPtr->ShouldDelete())
{
delete pPtr;
previousNode->next = nextNode;
}
else
{
previousNode = pPtr;
}
pPtr = nextNode;
}
Notice that no specific if-tests within the for-loop on nullptr are needed. You should tell the previous node that it now points to the next of the deleted one. If there is no next one, the previous->next will just point to a nullptr, indicating the end of the list.
The second problem is that you don't have any clear 'start of the list'. In my example code above, it becomes quite hard to indicate what the previousNode is. Is it a nullptr? But what if we remove the first element?
You could easily add logic here to indicate keep track of the first element, initialize previousNode to nullptr, and if the first is deleted, just don't set previousNode->next' and keep previousNode equal tonullptr` in that case, but what about the caller? How can the caller know that the first element has been deleted and the list now starts later.
My preferred solution is to have a separate List struct/class, and keep the start of the list (the first Node) as a member in the List struct/class. Instead of passing the startNode to the function, you should pass the List instance.
The code in the while-loop now becomes a bit longer, since you need to adapt previousNode->next=nextNode to this:
if (previousNode)
previousNode->next = nextNode;
else
list->firstNode = nextNode;
If you don't want to introduce a new List struct/class, you could also return the new firstNode as return value from your function, like this:
if (previousNode)
previousNode->next = nextNode;
else
startNode = nextNode;
…
return startNode;
Notice that this second approach only works if the caller if the function is also the one maintaining the list, and there are no other places pointing to the startNode.
In any case, if multithreading is involved, you probably want a decent List class with a kind of mutex (ideally std::list decorated with a mutex).
I am writing a method to Delete duplicate-value nodes from a sorted linked list in c++. I'm trying to use Node* instead of void return type but facing an error because of the return statement.
My method code..
Node* RemoveDuplicates(Node *head)
{
struct Node* current = head;
struct Node* next_next;
if(current == NULL)
return;
while(current->next != NULL)
{
if(current->data == current->next->data)
{
next_next = current->next->next;
free(current->next);
current->next = next_next;
}
else
{
current = current->next;
}
}
}
The compile time error message i am receiving..
solution.cc: In function 'Node* RemoveDuplicates(Node*)':
solution.cc:31:6: error: return-statement with no value, in function returning 'Node*' [-fpermissive]
return ;
^
Change the return type to void.
There is nothing valuable to be returned from the function.
The compiler doesn't pretend to know what you are thinking, he asks you to make contracts on what is going on. Hence, declaring the return type Node* you must provide an output of that specific type : a Node pointer. The most likely scenario I can imagine here would be returning the current node without the duplicates at the end of the function.
Node* RemoveDuplicates(Node *head)
{
// some instructions
return head;
}
so you can have this kind of semantic :
Node* distinctList = RemoveDuplicates(head);
if (distinctList) // NULL (0 / false) if empty
{
// some more instructions
}
However, if you don't need anything to go out of the function, the return type should be void (nothing).
Hope this helps!
I will treat this as a learning exercise, and ignore the fact that it is preferable to use a std list than to implement your own linked list, and it is preferable to use new and delete to using malloc and free.
If you specify Node* as a return type, you must return a pointer to a node. In order to answer your question, you have to ask is: what pointer do you want to return? As written you are deleting all duplicate pointers. Do you want to return the last pointer deleted? Do you want to loop until you find a duplicate and delete that?
You have two exit points in your code snippet. The first is a plain "return" statement, which is called when the list is empty. As written you are returning void, i.e. nothing. You need to return a pointer to a Node, but you have no valid pointers, so you probably want to return a null_ptr, which is a pointer to nothing.
Now we come to the part of your question which depends on the desired behavior. For example:
while(current->next != NULL)
{
if(current->data == current->next->data)
{
next_next = current->next->next;
free(current->next);
current->next = next_next;
/// Here you have a valid pointer you could return:
return current;
}
else
{
current = current->next;
}
// if you get here, no duplicates were found, so you can return a nullptr.
return std::nullptr;
}
Will loop over your list until a duplicate is found, will delete that duplicate, and return a pointer to the remaining pointer. If no duplicates are found, a nullptr is returned.
I leave it as an exersize to modify this to loop over all elements in the list until the last duplicate is found (hint, you will have to introduce a local variable to store the return value), and return that.
Good luck.
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.
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!