Having a little trouble with pointers - c++

The below is meant to reverse a linked list. It seems to work till it gets to the last line. When I debug, both "current" and "result" are of the same type (Node*) and "result" is the list reversed. But when the function completes, current only has the first value of the "result" list. Anyone know why "current" is not the full list when the function completes?
struct Node {
int data;
Node* next;
};
void reverseList(Node** head)
{
Node* current = *head;
Node* result = NULL;
while (current != NULL)
{
Node* temp = current;
current = temp->next;
temp->next = result;
result = temp;
}
current = result;
}

There are multiple problems with the shown logic.
We can start with the obvious observation that the goal of reverseList is, apparently, to reverse a singly-linked list.
The second observation is that the function takes a single parameter, a pointer to the head node, and it returns a void.
From, that we conclude that the function should update the head node, but there's nothing in the code that does that.
Additionally, there's really no reason why this function should take a double pointer like that, a pointer to the head node, and update it. It's much simpler for the function to take an ordinary pointer to the first element of the list, the existing head pointer, and then return the head pointer of the reversed list.
With this simple change, the resulting logic becomes much, much shorter and simpler:
Node *reverseList(Node *head)
{
Node *current=NULL;
while (head)
{
Node *next=head->next;
head->next=current;
current=head;
head=next;
}
return current;
}
That's it.

you need to update the head at the end of your algorithm:
current = result;
*head = current;

Related

Is this a effective way to delete entire linked list?

In function given below, I simply delete the head-pointer of the list and set head pointer to nullptr (im setting it nullptr because in my print function,I check for nullptr for head node, and ask user to create list first if head-node is nullptr).
void del_list(stud* &orig_head)
{
cout << "Deleting entire list..." << endl;
delete orig_head;
orig_head = nullptr;
}
I have a question regarding the way I choose to delete the list, since im not clearing each node of list, im simply clear the head pointer, what will happen to all the other nodes? Will this approach create a memory leak ?
Edit:
Im not using OOP to implement linked list,im implementing linked list using struct and couple of functions.
I like to handle this problem recursively:
void deleteNode(Node * head)
{
if(head->pNext != NULL)
{
deleteNode(head->pNext)
}
delete head;
}
If we have a list of 5 items:
head->pNext->pNext->pNext->pNext->NULL;
Then, the function will first get called for head, then for each pNext until the last one. When we reach the last one, it will skip deleting the next one (since it's null) and just delete the last pNext. Then return and delete the list from back to front.
This is assuming that each node's pNext is initialized to NULL. Otherwise, you'll never know when you've reached the end of the linked list.
Your code will cause memory leak. To delete it correctly, traverse the list and while traversing delete each node separately. And finally make head pointer to point to NULL value. You can have a look at the following code.
void deleteList(struct Node** head_ref)
{
struct Node* current = *head_ref;
struct Node* next;
while (current != NULL)
{
next = current->next;
free(current);
current = next;
}
//Now make head_ref point to null
*head_ref = NULL;
}

Queue implementation is losing track of head node

I have a queue add function implemented
void queue::add(myObj info)
{
node* node = new node;
node->info = &info; //<---suspect
node->next = NULL;
if(head == NULL){
head = node;
}
else{
tail->next = node;
}
tail = node;
count++;
}
Every time this gets visited the head node's data points to whatever I'm passing in. I realize there is a template for this but I am trying to build one, because I obviously need practice.
I am trying to keep all the pointers pointed to the original objects. I wanted to pass in the object and point to the refrence.
The node is a struct with myObj * info and node * next
info is a parameter of your function, that is passed by value. In this case, &info is the address of the parameter, and not of the original data.
This is undefined behaviour and can only give weird results.
One possible solution would be:
void queue::add(myObj& info) // pass by reference
{
... // unchanged code
}
In this case, &info would refer to the address of the original object.

The status of head in this linked list

My mind is confused at the moment:
struct Node {
int data;
struct Node *next;
}
void Print(Node *head) {
}
This is a code snippet from HackerRank. While this is easy, I just started wondering something: If I modify the head in the Print function, does it modify the original head in the main as well, or is it just the local variable head that is modified?
You passed in a pointer by value, if you modify that pointer then it will not affect the original.
However if you modify what is pointed to by that pointer then it will affect the original.
For instance head = nullptr; would not, while head->data = 1; would.
Also note that any recursion you do will similarly change the original data, for instance an algorithm to add to the end of the list:
Node* previous = head
Node* current = head->next;
while (current != nullptr)
{
previous = current;
current = previous->next;
}
previous->next = new Node(); //However you create one.
Since it uses head->next and eventually modifies the result it will modify the original list.

Linked list, add node to end

I'm working on a project and I was given this function to complete
void addToEnd(node*& head, string newVal)
Effect: adds new node to tail end of list
Precondition: head is a pointer to first node in the list (list MAY be empty)
Postcondition: list contains one more node
My question is what is the string newVal for?
The value_type of this class is of type DOUBLE so I'm confused what string newVal is for. So I can't set the newVal in the node because it is of two different types.
This is what I have so far. I'm not sure if im going in the right direction.
node *temp = new node;
temp = head;
while(temp->link() != NULL){
temp = temp->link();
}
head->set_link(temp);
I'm not even sure where to use the string in this block of code.
link() returns the member variable node* link_field
set_link() sets the new link to the link_field
Well, we're guessing that they somehow expect you to turn a string into a double with a function like std::stod.
As for your list manipulation code, there's a few problems:
node *temp = new node;
temp = head;
This creates a new node, puts its pointer in temp, then immediately overwrites temp with head, losing (leaking) the new node. Don't do that.
while(temp->link() != NULL){
temp = temp->link();
}
This is close, but might not work. The problem is that you need to keep track of the real node pointer, not a copy.
Normally, in a linked list API using pointers instead of references, the "add node" function looks like:
void addToEnd(node** head, string newVal)
{
while(*head)
head = &((*head)->next);
*head = new node;
(*head)->value = newVal;
(*head)->next = 0;
}
Note that if the list is empty, the passed-in head pointer is altered to point to the new node. If the list is not empty, the last next pointer is altered instead.
The API you're given (i.e. the link and set_link methods) doesn't allow this, because the head pointer is not a node and those functions require a node. So you've got to do it a little differently, namely you have to handle the empty list case separately.
void addToEnd(node*& head, string newVal)
{
// Create the node.
node* newNode = new node;
newNode->value = std::stod(newVal);
newNode->set_link(0);
if(!head) // Empty list?
{
head = newNode;
return;
}
// Find last node.
node* item = head;
while(item->link())
item = item->link();
item->set_link(newNode);
}

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.