I've started to learn linked lists today, and I am trying to delete nodes.
void deleteEnd(Node* refNode) {
Node* lastNode;
lastNode = new Node;
while((refNode->next)->next != NULL) {
refNode = refNode->next;
}
lastNode = refNode->next;
refNode->next = NULL;
delete lastNode;
}
void deleteIndex(Node* refNode, int index) {
Node *prev, *next, *deleted;
prev = new Node;
next = new Node;
deleted = new Node;
for(int i=1; i < index; i++) {
refNode = refNode->next;
}
prev = refNode;
deleted = prev->next;
next = deleted->next;
prev->next = next;
free(deleted);
}
I can use delete in the first one, but when I try to use it in the second, it doesn't work. The terminal doesn't give any error messages.
I found some information on the Internet, but I couldn't really understand it.
This is my linked list:
class Node {
public:
int data;
Node *next;
};
As pointed out by the comments, there are several things wrong with this code. All issues are from the comments, none are found by me, all credit goes to François Andrieux, Jesper Juhl, Sven Nilsonn, Avi Berger, and Thomas Matthews.
First, the code probably doesn't work because you mixed new and free. new is a C++ API function, while free is from C. Whenever you construct an object with new, which should not be that often with C++'s automatic memory management, you must free it with delete.
Second, when looping through a list, always start at 0. The only reason otherwise would be to start at the second item.
Third, in this passage:
prev = new Node;
...
prev = refNode;
...
prev->next = next;
When you set prev, it is overwriting the previous value. If this is a pointer, as it is, then this causes a memory leak. Always delete it before overwriting.
Finally, in deleteEnd, as pointed out by Thomas Matthews, you are trying to dereference, or get the value from, the pointers, without checking if it is nullptr. If one is, it will cause undefined behavior, and can crash the program.
Related
In many occasions, we need to modify a linked list drastically so we will sometimes create another linked list and pass it to the old one. For example,
struct node { //let's say we have a linked list storing integers
int data;
node* next;
};
and suppose we already have a linked list storing integers 1,2,3.
node* head; //suppose we already store 1,2,3 in this linked list
node* new_head ; //suppose we make a temporary linked list storing 4,5,6,7
head = new_head; //modifying the original linked list
My Question
If I delete head (the old linked list) before the assignment then the whole program will crash.
Conversely, if I do not delete it, then there will be a memory leak.
Therefore, I am looking for a way to modify the linked list without memory leak.
My attempt
I tried to make a helper function similar to strcpy to do my work.
void passing_node(node*& head1, node* head2){ //copy head2 and paste to head1
node* ptr1 = head1;
for (node* ptr2 = head; ptr2 != nullptr; ptr2 = ptr2->next)
{
if (ptr1 == nullptr){
ptr1 = new node;
}
ptr1->data = ptr2->data;
ptr1 = ptr1->next;
}
}
// note that we assume that the linked list head2 is always longer than head1.
However, I still got a crash in the program and I cannot think of any other way to modify this. Any help would be appreciated.
Easier way to avoid memory leak is to avoid raw owning pointers.
You might use std::unique_ptr (or rewrite your own version):
struct node {
int data = 0;
std::unique_ptr<node> next;
};
You can move nodes.
You can no longer copy nodes (with possible double free issue).
so deep_copy might look like:
std::unique_ptr<Node> deep_copy(const Node* node)
{
if (node == nullptr) return nullptr;
auto res = std::make_unique<Node>();
res->data = node->data;
res->next = deep_copy(node->next.get());
return res;
}
I would suggest preallocating the linked list so it's easy to delete every node in one call. The nodes would then just reference somewhere inside this preallocated memory. For example:
struct Node
{
int value;
Node* next;
};
struct LinkedList
{
Node* elements;
Node* first;
Node* last;
Node* free_list;
LinkedList(size_t size)
{
first = nullptr;
last = nullptr;
elements = new Node[size]{0};
free_list = elements;
for (size_t i = 0; i < size-1; ++i)
free_list[i].next = &free_list[i+1];
free_list[count-1].next = nullptr;
}
~LinkedList()
{
delete[] elements;
}
void Add(int value)
{
if (free_list == nullptr)
// Reallocate or raise error.
// Take node from free_list and update free_list to
// point to the next node in its list.
// Update last node to the new node.
// Update the first node if it's the first to be added.
}
void Free(Node* node)
{
// Search for the node and update the previous and
// next's pointers.
// Update first or last if the node is either of them.
// Add the node to the last place in the free_list
}
};
From here you'll have many strategies to add or remove nodes. As long as you make sure to only add nodes to the allocated elements array, you'll never have any memory leak. Before adding, you must check if the array have the capacity to add one more node. If it doesn't, you either have to raise an error, or reallocate a new the LinkedList, copy over all values, and delete the old one.
It becomes a bit more complicated when the array becomes fragmented. You can use a 'free list' to keep track of the deleted nodes. Basically, a LinkedList of all nodes that are deleted.
Just take notice that my code is incomplete. The basic approach is to create an allocator of some sort from which you can allocate a bulk, use segments of it, and then delete in bulk.
I am trying to implement a stack using a Linked List. My program keeps crashing and when trying to print the new Linked List, it prints an unsigned integer. My print function works fine, so it is this function below.
Please help.
void LinkedList::Push (int val)
{
Node* newHead = new Node;
Node* oldHead = new Node;
newHead->value = val;
oldHead = head;
head = newHead;
oldHead->prev = head;
head->next = oldHead;
delete newHead;
}
One issue is that the Node that you've newed in the definition of oldHead is never deleted. Since you set oldHead to head immediately after creating it, I would suggest this as your definition:
Node* oldHead = head;
The main issue, though, is that you delete newHead, which is now what head points to. Therefore, when you go to print head, you are reading invalid data.
I would highly recommend leaving the resource handling to objects like std::shared_ptr instead of newing and deleteing yourself.
I'm not sure I understood your question.
Your fixed method:
void Push( const int val )
{
Node* newNode { new Node };
newNode->value = val;
newNode->next = head;
head = newNode;
}
Read more about Linked List operations here. You do not need a doubly linked list to implement a stack - you only need to push/pop at one end.
[EDIT]
I didn't notice you are using a doubly linked list (this is why a complete/verifiable example is required). As I said, for a stack implementation, a singly linked list is enough.
There's 2 pieces of code that I can't seem to find the bug with. I know there is something wrong within these. One for each.
int pop()
{
Node* temp = new Node();
temp = tail;
tail->prev()->setNext(NULL);
int tempV = temp->key();
delete temp;
return tempV;
}
The other piece of code is this:
int main()
{
Node* t = new Node(0,NULL);
t = Node(1,t);
t = Node(2,t);
delete t;
}
I thought about the 2 pieces of code for a while. For the 1st piece of code, I think the error is that you shouldn't create the Node* temp on the heap with the keyword new. It should just be Node* temp = tail; I believe. Can anyone confirm that?
For the 2nd piece of code, I thought the error was that you don't need both
t = Node(1,t);
t = Node(2,t);
EDIT::I'm sorry I made a mistake. It was supposed to be Node rather than node. My friend told me it has to do something with memory. It there a memory leak because of the multiple nodes being declared with new? Or do we need the new keyword for the last 2?
Thanks
When you pop the element, you need not create a "new" node. You have to remove the last element of the linked list - not create a new node.
For your second question, you do not need the
t = node(1,t)
t = node(2,t)
if the function returns the currently added node.
But if the function returns the header of the linked list, it is required. It depends on how you write the node function.
you are losing the value you new
Node* temp = new Node();
temp = tail; <-- you just lost the value you new'ed
then later you are deleting a different node
tail->prev()->setNext(NULL); <-- this line doesn't check that the value for prev() isn't null
as to what is going on in main I would need to see more of the code for "node"
Dinesh is correct in the first example. Here is a little more explanation.
Node* temp = new Node()
temp = tail;
results in a memory leak. the new node that was created is leaked when you overwrite temp to tail. The proper way to do it would be
Node * temp = tail;
In the second example its not clear what the node function does. If you meant to write this:
int main()
{
Node* t = new Node(0,NULL);
t = new Node(1,t);
t = new Node(2,t);
delete t;
}
The code would make more sense, it creates a linked list of three nodes containing 2, 1, 0 when listed from head to tail. It's hard to tell from the incomplete example.
In pop you have a memory leak. You construct a Node on the heap and then immediately lose track of it, like inflating a balloon and letting it go:
Node* temp = new Node();
temp = tail;
But you also have a more serious problem: you do not adjust tail. When the function is finished, tail points to a region of memory where the last node used to be, and any attempt to dereference it will cause Undefined Behavior.
As for your second question, the code might be correct, and it might not. There's no way to tell unless/until you show us what node(...) does.
I'm trying to learn C++ and there is a small confusion I have.
The text which I am learning from tells me that if I want to delete a node of type const T& I should first create a new pointer of that node type, then delete it using the inbuilt C++ delete[]. However, what happens if I just set the link from the to-be-deleted node's previous element to the to-be-deleted node's next element? Something like:
*p = node.previous;
p-> next = node.next;
Or will this cause a memory leak?
I'm confused because I read somewhere else to never, ever delete pointers willy-nilly, but the example code I am working with has something along the lines of:
Node<T> *p = node-to-be-deleted;
delete p;
What is the best way to delete the node?
Assuming your node looks like this:
struct Node
{
Node* previous;
Node* next;
SomeType data;
};
Then:
*p = node.previous;
p-> next = node.next;
Then YES. This will cause a memory leak.
It also leaves p->next->prev pointing at the wrong node.
I'm confused because I read somewhere else to never, ever delete pointers willy-nilly, but the example code I am working with has something along the lines of:
Yes the best way is to "never delete pointers". But this has to go along with some context. You should not be deleting pointers manually because pointers should be managed by an objects that control their lifespan. The simplest of these objects are smart pointers or containers. But for this situation that would be overkill (as you are creating the container).
As you are creating the container (a list) you will need to do the management yourself (Note C++ already has a couple of lost types std::list for a list of values of type t or boost::ptr_list for a list of pointers to T). But it is a good exercise to try and do it yourself.
Here is an example on code review of a beginner making a list and the comments it generated:
http://codereview.stackexchange.com: Linked list in C++
I hope this helps in explains on how to create and delete objects.
Node* p = new Node; // This is how you allocate a node
delete p; // This is how you delete it
The delete[] operator should be used on dynamically allocated arrays:
Node* nodelist = new Node[ 4 ]; // nodelist is now a (dynamically allocated) array with 4 items.
delete[] nodelist; // Will delete all 4 elements (which is actually just one chunk of memory)
Deleting a Node directly only makes sense if Node implements a destructor to update the previous and next pointers of the surrounding Node instances, eg:
Node::~Node()
{
if (previous) previous->next = next;
if (next) next->previous = previous;
}
Node *p = node-to-be-deleted;
delete p;
Otherwise, you have to update the Node pointers before then deleting the Node in question, eg:
Node *p = node-to-be-deleted;
if (p->previous) p->previous->next = p->next;
if (p->next) p->next->previous = p->previous;
delete p;
With that said, the best approach is to no implement a linked list manually to begin with. In C++, use a std::list container instead, and let it handle these details for you.
void deleteNode( Node * p )
{
Node * temp = p->next;
p->data = p->next->data;
p->next = temp->next;
free(temp);
}
Heres something i did a few months ago.
template <class T>
T LinkedList<T>::remove(int pos)
{
if (pos < 1 || pos > size)
{
throw pos;
}
ListNode * temp;
if (pos == 1)
{
temp=head;
head = head->next;
}
else
{
int i=1;
ListNode * prev = head;
while(i<pos-1)
{
i++;
prev=prev->next;
}
temp = prev->next;
prev->next = (prev->next)->next;
}
--size;
return temp->item;
}
I need to implement an auxilliary function, named copyList, having one parameter, a pointer to a ListNode. This function needs to return a pointer to the first node of a copy of original linked list. So, in other words, I need to code a function in C++ that takes a header node of a linked list and copies that entire linked list, returning a pointer to the new header node. I need help implementing this function and this is what I have right now.
Listnode *SortedList::copyList(Listnode *L) {
Listnode *current = L; //holds the current node
Listnode *copy = new Listnode;
copy->next = NULL;
//traverses the list
while (current != NULL) {
*(copy->student) = *(current->student);
*(copy->next) = *(current->next);
copy = copy->next;
current = current->next;
}
return copy;
}
Also, this is the Listnode structure I am working with:
struct Listnode {
Student *student;
Listnode *next;
};
Note: another factor I am running into with this function is the idea of returning a pointer to a local variable.
The first question you need to ask yourself is what the copy semantics are. In particular, you're using a Student* as node contents. What does copying node contents mean? Should we copy the pointer so that the two lists will point to (share) the same student instances, or should you perform a deep copy?
struct Listnode {
Student *student; // a pointer? shouldn't this be a `Student` object?
Listnode *next;
};
The next question you should ask yourself is how you will allocate the nodes for the second list. Currently, you only allocate 1 node in the copy.
I think you code should look more like:
Listnode *SortedList::copyList(Listnode *L) {
Listnode *current = L;
// Assume the list contains at least 1 student.
Listnode *copy = new Listnode;
copy->student = new Student(*current->student);
copy->next = NULL;
// Keep track of first element of the copy.
Listnode *const head = copy;
// 1st element already copied.
current = current->next;
while (current != NULL) {
// Allocate the next node and advance `copy` to the element being copied.
copy = copy->next = new Listnode;
// Copy the node contents; don't share references to students.
copy->student = new Student(*current->student);
// No next element (yet).
copy->next = NULL;
// Advance 'current' to the next element
current = current->next;
}
// Return pointer to first (not last) element.
return head;
}
If you prefer sharing student instances between the two lists, you can use
copy->student = current->student;
instead of
copy->student = new Student(*current->student);
This is an excellent question since you've done the bulk of the work yourself, far better than most "please do my homework for me" questions.
A couple of points.
First, what happens if you pass in an empty list? You probably want to catch that up front and just return an empty list to the caller.
Second, you only allocate the first node in the copy list, you need to do one per node in the original list.
Something like (pseudo-code (but C++-like) for homework, sorry):
# Detect empty list early.
if current == NULL:
return NULL;
# Do first node as special case, maintain pointer to last element
# for appending, and start with second original node.
copy = new node()
last = copy
copy->payload = current->payload
current = current->next
# While more nodes to copy.
while current != NULL:
# Create a new node, tracking last.
last->next = new node()
last = last->next
# Transfer payload and advance pointer in original list.
last->payload = current->payload
current = current->next
# Need to terminate new list and return address of its first node
last->next = NULL
return copy
And, while you're correct that you shouldn't return a pointer to a local stack variable, that's not what you're doing. The variable you're returning points to heap-allocated memory, which will survive function exit.
I have been trying to do the same thing. My requirements were:
1. Each node is a very basic and simple class (I moved away from the struct model).
2. I want to create a deep copy, and not just a pointer to the old linked list.
The way that I chose to do this is with the following C++ code:
template <class T>
Node <T> * copy(Node <T> * rhs)
{
Node <T> * current = new Node<T>();
Node <T> * pHead = current;
for (Node <T> * p = rhs; p; p = p->pNext)
{
Node <T> * prev = current;
prev->data = p->data;
if (p->pNext != NULL)
{
Node <T> * next = new Node<T>();
prev->pNext = next;
current = next;
}
else
{
prev->pNext = NULL;
}
}
return pHead;
}
This works well, with no errors. Because the "head" is a special case, there is a need for my implementation of a "current" pointer.
The statement
copy->next = current->next
is wrong. You should do
Create the first node copy here
copy->student = current->student;
copy->next = NULL;
while(current->next!=NULL)
{
Create new node TEMP here
copy->next = TEMP;
TEMP->student = current->student;
TEMP->next = NULL;
copy = TEMP;
}
Since you need a copy of the linked list, you need to create a new node in the loop while traversing through the original list.
Listnode *startCopyNode = copy;
while (current != NULL) {
*(copy->student) = *(current->student);
copy->next = new Listnode;
copy = copy->next;
current = current->next;
}
copy->next = NULL;
return startCopyNode;
Remember to delete the nodes of linked list.
#pat, I guess you will get a seg_fault, because you create memory only once. You need to create memory(basically call 'new') for each and every node. Find out, where you need to use the 'new' keyword, to create memory for all the nodes.
Once you are done with this, you need to link it to the previous node, since its a singly linked list, you need to maintain a pointer to the previous node. If you want to learn and should be able to remember all life, don't see any of the code mentioned above. Try to think the above mentioned factors and try to come up with your own code.
As others have pointed out, you need to call new for each node in the original list to allocate space for a copy, then copy the old node to the new one and update the pointer in the copied node.
another factor I am running into with this function is the idea of returning a pointer to a local variable.
You are not returning a pointer to a local variable; when you called new, you allocated memory on the heap and are returning a pointer to that (which of course means that you need to remember to call delete to free it when you are done with the new list, from outside the function).