struct node {
string info;
node *next;
node() {
info = "string";
next = NULL;
}
};
void insert(node &anode) {
node newNode;
anode.next = &newNode;
}
What is wrong with this implementation of insert for this structure ? How should I fix this?
added: Very sorry that I wasn't clear. I know what is wrong with the program. I want to know how I can insert a new node to a reference node. Since I am using a reference to a node as a param this mean that node must not be a pointer? So its stored on stack? which means I can't use memory from heap? (or else seg fault?) so how am I suppose to use new ? This is my main confusion. Perhaps my approach is wrong but I don't see why it should be.
What's wrong is that newNode lives in the scope of the insert function. You probably want something like
void insert(node &anode) {
node* newNode = new node;
anode.next = newNode;
}
but the parent node, or something else, then has to take care of the new node's lifetime. It now owns the next node. If you want the caller to be in charge, then this might be more suitable:
void insert(node& parentNode, node& nextNode) {
parentNode.next = &nextNode;
}
Note that you can avoid some of the lifetime issues by using boost::shared_ptr or std::shared_ptr if you have access to C++0x. These smart pointers basically wrap a pointer and take care to delete it when nobody is using it. The code would look something like this:
struct node {
// other data members...
shared_ptr<node> next;
// constructors/destructors
};
void insert(node& anode) {
anode.next = shared_ptr<node>(new node);
}
Now you don't have to worry about deleting the new node at any point.
You're returning (implicitly, as member of anode) a pointer to the local variable newNode. newNode is destroyed when you're leaving insert, so anode.next contains an invalid pointer afterwards.
BTW: should this question be tagged "homework"? :)
The "what's wrong" has nothing to do with references.
This implementation stores a pointer to a local variable in anode.next. Local variable gets destroyed immediately afterwards (when insert function exists), while the pointer continues to live pointing into a destroyed location.
The problem is that the local variable newNode will go out of scope once the function insert exists, and anode.next will now reference an invalid node.
Assuming that you are talking about a runtime error. The problem is that in your insert function
node newNode
is only a local variable, and it will be causing a problem when you try to access it later while iterating on the node(s).
Inside the insert function you should be doing something like this:
node* newNode = new node();
anode.next = newNode;
If you insist on using free functions, your best bet is probably something like:
static node* head = NULL;
static node* current = NULL;
void insert(std::string& val)
{
if (!head) {
current = new node(val);
head = current;
} else {
current->next = new node(val);
current = current->next;
}
}
and having your constructor accept an std::string as an argument. Relying on an entity outside the function to create nodes for you is probably not the best idea. You can pseudo-encapsulate that by creating nodes on demand when you call insert. Then you can run through the nodes using the head pointer and consequently delete them when you're finished with the list.
You are using a static address.
void insert(node &anode) {
node newNode;
anode.next = &newNode;
}
newNode is a local object. At the end of the function, it will go out of scope and its address will be invalid.
Related
The Definition of the structure is as follows.
//Structure of the linked list node is as follows:
struct Node {
int data;
struct Node* next;
Node(int x) {
data = x;
next = NULL;
}
};
I have to complete this function which I have completed this way. I am trying to create a Node using the newData parameter passed in the function definition. But it shows the error which I have attached below.
// function inserts the data in front of the list
Node* insertAtBegining(Node *head, int newData) {
//Your code here
struct Node* newNode(newData);
struct Node* temp;
temp=head;
head=newNode;
newNode->next=temp;
}
I get this error while I am create a node by passing newData as parameter to struct Node *newNode(newData);
In function Node* insertAtBegining(Node*, int):
prog.cpp:67:32: error: invalid conversion from int to Node* [-fpermissive]
struct Node *newNode(newData);
Thank You for your help.
Your constructor returns a Node, not a Node*, so when you try to initialize newNode, the compiler thinks you're trying to create a pointer using an int. Instead you should be expecting your constructor to give you a Node:
Node newNode(newData);
Your insertAtBegining() implementation needs to create a new Node object. You aren't doing that. Right after your teacher's Your code here comment, your attempt has defined a "Node pointer" variable (whose type is Node*), but your attempt hasn't initialized that to any Node object (data that would have been passed to an object's constructor isn't the same as the object itself).
Also, you don't need to keep repeating struct that way that us old guys used to do with old-fashioned C code.
Lastly, you seem to also want to return the list's new head node back to the function's caller, but are unclear how you want to achieve that. There are two ways. The way that your code seems to be leaning towards is returning the new head in the same head parameter. In that case, it should look like this:
void insertAtBegining(Node** head, int newData)
{
//Your code here
Node* newNode = new Node(newData);
Node* temp;
temp = *head;
*head = newNode;
newNode->next = temp;
}
(The head parameter could also have been a "reference to a Node*", instead of this "pointer to a Node*", by making appropriate changes to the code.)
The second option (which maintains your teacher's recommended function signature) is to return the new head via the function's return value:
Node* insertAtBegining(Node* head, int newData)
{
//Your code here
Node* newNode = new Node(newData);
newNode->next = head;
return newNode;
}
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.
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.
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.
// 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.