How does this pop-function work? - c++

I would like to understand the following pop-function.
struct list_node{
int key;
list_node* next;
list_node(int k, list_node* n)
: key(k), next(n);
{}
};
class stapel{
private: list_node* top_node;
public: void pop (int value);
};
void stapel::pop()
{
list_node* p=top_node;
top_node=top_node -> next;
delete p;
}
I know the pop-function removes the topmost node of a stack. So you have a pointer p, that points to the same node like the pointer top_node. I have difficulties understanding the next line. top_node->next means the same like (*top_node).next and top_node is of type list_node, which is like a box that consist a key, a next-pointer and their values. Now I can't understand what top_node->next really means. I know next will become the next top_node pointer but why?

void stapel::pop()
{
list_node* p = top_node; // Get pointer to top of stack
top_node = top_node->next; // Find the next item in the stack, assign it to now be the top
delete p; // Delete the current top
}
You basically told the stack that the new "top" is the node that used to be 2nd from the top. You then delete the top node.
The way that the next line is working, is the same way that a "linked list" works. When you construct the stack (or linked list), for each node, you assign the value of that node (key), and a pointer to the next node (next).
top_node = top_node->next;
is simply getting the next member variable of the current node. That member variable happens to be a pointer to the next node, which was assigned when the current node was inserted into the stack.
Edit
As #Edward noted, it would also be a good idea to check that top_node is not nullptr. If it were, you would hit an exception when you tried to access the next member. So you could modify this function as:
void stapel::pop()
{
if (top_node == nullptr)
return;
list_node* p = top_node;
top_node = top_node->next;
delete p;
}

Related

Pointer to pointer assignment and dereference in C++

Let's say I have a linked list node like the following:
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
The goal is to write a function to delete a node in a singly-linked list. One efficient way to do it in constant time is something like this:
void deleteNode(ListNode* node) {
auto *tmp = node->next;
*node = *tmp;
delete tmp;
}
This works, but why do we need to dereference the pointers?
If node is a pointer and tmp is a pointer, why does it need to dereferenced? Why can't I do node = tmp?
When performing *node=*tmp you copy all the bytes of *tmp into *node thus
node->val now holds tmp->val and node->next now holds tmp->next.
The old content of node has been forgotten (it's normal since you want to get rid of this node) but you saved the content of the next node at this same place.
Then if you delete the next node (known through tmp) you don't lose its content (it has been saved in the previous node).
Let's break down the three lines of your deleteNode function:
auto *tmp = node->next;
This creates a local variable, tmp which will be a copy of the next field of the passed node parameter. This is a pointer to the next structure in the list and, once we've made a copy of it, we can erase or overwrite that member.
*node = *tmp;
This copies the actual data of the structure pointed to by tmp (that is, the next node in the list) to the current node, overwriting the next field as it does so. We need to dereference both pointers in order to copy the values of the structures pointed to.
delete tmp;
This deletes the 'next' node in the given list. However, we have already copied all its data (including its next member) into our current node, so our modified list now starts with (effectively) the second one in the original list (the passed parameter); notably, the next field of *node will now be the address originally stored in node->next->next – thus, we have 'skipped' an entry (the second) in the list and deleted it.
The reason you can't just write node = tmp is because that wouldn't change anything outside of your function.
Given this linked list
node0 -> node1 -> node2 -> node3
If you want to delete node1, the desired outcome would be
node0 -> node2 -> node3
If you don't want to actively modify the pointer value (that is, the address next) in node0, you have to move the value inside node2 to where node1 was.
Why can't I do node = tmp ?
You can do that, but it won't do anything useful. node is a local variable in deleteNode. As it is a pointer you can use that local pointer to modify what it points to, but modfying the pointer itself has no effect outside of the function.
Actually pointers are not different with respect to that. You also cannot observe any effect from outside when you have
void foo(int x) {
x = 42;
}
Passing a reference is different:
void bar(int& x) {
x = 42;
}
int a = 0;
bar(a); // now a == 42
Same with pointers:
void bar_ptr(int*& x) {
x = nullptr;
}
int* b = &a;
bar_ptr(b); // now b == nullptr
If you do node = tmp and after that delete tmp you will be deleting the ListNode, which node points to.
As others pointed out, node = tmp just changes the argument(local variable)
*node = *tmp is to copy the content of ListNode which is equivalent to
node.val = tmp.val; node.next = tmp.next
This function actually removes the next element - it works, but it invalidates the next pointer(if there was something that refers node->next as a pointer, it is now a dangling pointer)
What your function really does, is that it doesn't delete the node from the parameter, but the next node, overwriting the current node with the follower.
The dereferencing of the pointer acts like a memcpy() and moves the data from the next node to the current. You are not copying the pointers but the data it points to.
This way you can repeatedly call the function with the same node pointer, and it will move down the chain.
However, since you are not checking the pointer, the last node probably has a NULL pointer and will crash on derefencing.
So you need to do
if (tmp)
*node = *tmp;
Example:
typedef struct list
{
struct list *next;
int value;
} List;
void deleteNext(List* node)
{
auto *tmp = node->next;
if(tmp)
*node = *tmp;
delete tmp;
}
int main(int argc, char *argv[])
{
List *l0 = new List;
List *l1 = new List;
l0->value = 0;
l0->next = l1;
l1->value = 1;
l1->next = NULL;
deleteNext(l0);
deleteNext(l0); // Without the 'if' it will crash here.
return 0;
}
but why do we need to dereference the pointers?
Let's explore what happens if we don't indirect through the pointers:
auto *tmp = node->next;
node = tmp;
delete tmp;
This would be equivalent to just
delete node->next;
// resulting structure
previous node next (deleted) next next (leaked)
1---------->2----dangling--->_ 4
// desired structure that we get from the correct code
previous node next (deleted) next next
_
1-----------3---------------------------------->4
So, we end up with wrong node being deleted, and with a dangling pointer in the node that was supposed to be deleted.
Note that even the correct inirecting version is broken when attempting to delete the last node.

double linked list head dereferenced is null

my head pointer is supposed to be null, because I don't want
it to have any value when I make my linked list.
I know that you can't dereference something that is null,
but I just want to point it's next node to something new.
can someone explain how I could point the head node pointer?
void dlist::push_front(int value) {
node *p = new node();
node *tempH = head();
tempH->next = p; //break
/***********************************************************
my head pointer is suposed to be null, because I don't want
it to have any value when I make my linked list.
I know that you can't dereference something that is null,
but I just want to point it's next node to something new.
can someone explane how I could point the head node pointer?
************************************************************/
p->value = value;
p->next = tempH->next;
p->prev = tempH;
p->next->prev = p;
p->prev->next = p;
}
#pragma once
#include <ostream>
class dlist {
public:
dlist() {}
// Implement the destructor, to delete all the nodes
//~dlist();
struct node {
int value;
node* next;
node* prev;
};
node* head() const { return _head; }
node* tail() const { return _tail; }
void push_front(int value);
private:
node* _head = nullptr;
node* _tail = nullptr;
};
in your list constructor, simply set the head pointer to null.
dlist::dlist() {
_head = nullptr;
}
Further, if you end up removing the LAST item in your list, you will need to also make _head = nullptr;
Be sure to check if the head is null before dereferencing.
if(_head == nullptr){
_head = new node(...);
}
Your insert function will be responsible for assigning the first node to the head, in the event that you're adding to an uninitialized list.
If your list needs to be sorted, you will need to account for the head changing in the event that the new node should precede the head node.
The most practical solution here is to just use sentinel nodes for your head and tail. Or, just one sentinel node, that stands in for both. The sentinel nodes' elements can just be left uninitialised, you only need those nodes for the next and prev pointers they contain. To test if you've reached the end of the list, instead of testing for a null pointer, you test whether the pointer points to the sentinel node.
You can just use normal nodes as your sentinels if you expect your list elements to be small, or your lists to be very large. You waste a bit of memory on space for elements that won't be used, but it's probably not a big deal. If you really care about memory efficiency (say, you're writing a library), you can have something like this:
template<typename T> class dlist {
struct node_header {
node_header* next;
node_header* prev;
};
struct node : public node_header {
T element;
};
// Convert a node_header pointer to a node pointer
node* node_from_header(node_header* p) {
return static_cast<node*>(p);
}
};
With this approach, your sentinel node is a node_header and all your actual, element-containing nodes are nodes. Your internal algorithms all work on node_headers, until you need to actually retrieve the element of a node, at which point you use node_from_header() to retrieve the full, element-containing node.
If you absolutely want to not use sentinel nodes, you'll have to rewrite your code to directly use the head pointer, rather than retrieving it through a function, and add special-case code for handling a null head pointer. It's not a pretty option.

Does this cause memory leak when I call the deconstructor?

I have a data structures project I have to do for my Uni class which is to implement a stack with a linked list; simple stuff. We have had some help, code-wise, to show us the correct way to implement such a structure.
Stack class:
class Stack
{
public:
Stack(void)
{
top = NULL; // Initialises defualt top node pointer.
}
~Stack(void)
{
while (NodePop() != NULL){}
}
void Push(int value) // Pushes a new node onto the stack.
{
Node* temp = new Node(value, top); // Creates a temporary node with a value and makes it
// point to the top node as the next node in the stack.
top = temp; // Temporary node becomes the top node in the stack.
}
Node* NodePop(void)
{
/* Remove top node from the stack */
Node* temp = top; // Creates a temporary node to return, sets it to top node.
if (top != NULL) top = top->getNext(); // Points the stacks top node to the next node in the list.
return temp; // Returns a pointer to the popped node still in the heap.
}
int Pop(void) // Pops the top node off of the stack. Returns the nodes value.
{
Node* temp = NodePop();
int valueReturn = 0;
/* Sets the return value */
if (temp != NULL)
{
valueReturn = temp->getVal(); // Set return value to the nodes value if there is a node left.
}
else
{
throw "Stack Empty"; // Throws exception if temp is NULL and stack is empty.
}
delete temp; // Deletes the node entirely from the heap.
return valueReturn;
}
private:
Node* top;
};
Node class:
class Node
{
public:
Node(int value, Node* nextptr = NULL, Node* prevptr = NULL, int currentpriority = 0)
{
/* Set initial variables for the node at creation */
this->value = value;
this->next = nextptr;
this->prev = prevptr;
this->priority = currentpriority;
}
// bunch of getters and setters...
private:
Node* next; // Pointer to the next node.
Node* prev; // Pointer to the previous node.
int priority; // Stores the node priority as a number 0-9.
int value; // Stores the node value for printing.
};
We cannot change any of the classes structure (too my annoyance, NodePop() should be private, but w/e).
So here NodePop() essentially removes the top node from the list but doesn't delete it; it removes all reference to it from the linked list but it never deletes it from the heap, it's only deleted from the heap in Pop(). All good (except for being able to call NodePop() publicly, but again, I'm not allowed to make it private). But when I call the destructor is has to use NodePop(), not Pop().
So does that mean the node is never deleted from the heap when NodePop() runs from the destructor?
If so how would I delete them because it's going to run nodePop() if i have it in a while, do-while, or if statement condition so there will always be one node left undeleted?
Looking at the code in question
~Stack(void)
{
while (NodePop() != NULL){}
}
Node* NodePop(void)
{
/* Remove top node from the stack */
Node* temp = top; // Creates a temporary node to return, sets it to top node.
if (top != NULL) top = top->getNext(); // Points the stacks top node to the next node in the list.
return temp; // Returns a pointer to the popped node still in the heap.
}
Your destructor calls NodePop() until that function returns NULL. Let's look at what NodePop() does. The comment in the code claims that it Creates a temporary node to return That is not true. It creates a pointer to a Node (a Node*) and sets that pointer to point the same place that top does. If top is not null, it sets top to point to top's next node. It the returns temp, which is a pointer to what was originally the top Node.
At no point to you release memory associated with any Node, so yes there is a memory leak.
You can fix the leak by deleting each Node* that you encounter in the destructor that is not NULL.
Indeed, the nodes are not deleted, and this code will leak. You can verify that by using a tool like Valgrind.
I would change the while to something like while (Node *N = NodePop()) delete N;
FYI, this code is definitely not idiomatic C++11. It's basically poorly written C, and I'd expect to find more bugs in it. Your teacher should get a slap on the wrist for presenting C++11 like this :-)

Printing a linked list in C++ (C++98)

I'm attempting to print the nodes in a linked list (forwards direction).
It's defined as follows:
struct Node {
string val;
Node* next;
Node* prev;
};
struct Stew {
Node* first;
Node* last;
};
Where Stew has two special pointers, one pointing to the first element, and one to the last.
I'm positive that what I attempted is correct, but it's actually not.
void print (const Stew& q, char direction) {
assert (!isEmpty(q));
{
Node* current = new Node;
current = q.first;
cout << current -> val;
while((current -> next) != NULL)
{
current = current -> next;
cout << (current -> val);
}
delete current;
}
I know there's a logic mistake in there, but I can't seem to pinpoint it. Any help would be appreciated.
Why do you do not read answers on your question? I already showed you how to print the list in the direct and reverse order. See here.
Implementing a push function in c++
I think your problem might be that you are treating your current pointer like it is an object. Current is a pointer that simply points to another object in memory. Hence your line Node *current = new Node is meaningless and you are losing that Node in memory. Your problem is probably the last line where you delete current. Current is pointing to the last item in your list and when you call delete you are freeing the memory current points to. Hence you are deleting the last object in your list. You only need to use delete when you are creating an object in memory, and current should not be a new item it should be a pointer to existing memory.
First:
Node* current = new Node;
That is totally unnecessary. You don't want to create a new node from the heap. All you want to do is point current node to the head node:
Node* current = q.first;
Then assuming that current is a valid node, and the next pointer will either point to the next valid node or NULL to denote the end of the list, your while() loop is starting off wrong. It should be something like this:
while(current != NULL)
{
cout << current->val;
current = current->next;
}
And of course, remove the call to "delete" at the end.

Can we delete the last node of a Single Linked list if we only know the address of last node

// Variables
typedef struct node
{
int value;
struct node *next;
}mynode;
// Globals (not required, though).
mynode *head, *tail, *temp;
// Functions
void add(int value);
// Function to add new nodes to the linked list
void add(int value)
{
temp = (mynode *) malloc(sizeof(struct node));
temp->next=(mynode *)0;
temp->value=value;
if(head==(mynode *)0)
{
head=temp;
tail=temp;
}
else
{
tail->next=temp;
tail=temp;
}
}
// The main() function
int main()
{
head=(mynode *)0;
// Construct the linked list.
add(1);
add(2);
add(3);
return(0);
}
If I only have a pointer to a node, whose value is 3(The Last node as seen in the aforementioned code) , Can we delete it and make a node whose value is 2(aforementioned code) as the last node.
No you can not. Unless you have some reference to previous node. like head pointer. If you have other reference than its pretty much easier. In fact if you don't have any pointers you will loose the list itself
No, but if you know what you are doing, you can modify the last node in-place. Deleting the last node requires access to the second-to-last node, and specifically its link to the last node.
The answer is no.
You can call free on that pointer to the last node, but that just means that the memory occupied by that node is no longer claimed. The data will most likely stay there unchanged for a while. And that means that the next-to-last node's pointer to it is still valid, even though it should not be.
To delete the node in a way that is meaningful to the list, that pointer contained in the next-to-last node has to be nullified. And that can't be done unless that next-to-last node can be accessed, either by a direct pointer to it, or by traversing the list from a preceding node.
You can use a doubly linked list to access the previous node. Or iterate through the entire list.
Yes you can.. Try the following code:
void deleteNode()
{
mynode *temp1;
for(temp1 = head; temp->next!= tail; temp1 = temp1->next);
tail = temp1;
free(tail->next);
}
It will delete the last node.