Pointer initialization - c++

Sorry if this question has been asked before. On my search through SO I didn't find one that asked what I wanted to know.
Basically, when I have this:
typedef struct node
{
int data;
node *node;
} *head;
and do node *newItem = new node;
I am under the impression that I am declaring and reserving space, but not defining, a pointer to struct node, is that correct?
So when I do
newItem->data = 100 and newItem->next = 0
I get confused. newItem = 0would declare what exactly? Both data and next? The object as a whole?
I'm especially confused when I use typedef. Which part is the macro? I assume node because that's how I call it, but why do I need it?
Finally, what happens when I do:
node *temp;
temp = new node;
temp = head->next;
head->next = newItem;
newItem->next = temp;
I mean, head->next is a pointer pointing to object newItem, so I assume not to newItem.data or next themselves. So how can I use an uninitialized pointer that I described above safely like here? is head now not pointing to an uninitialized pointer?

I am under the impression that I am
declaring and reserving space, but not
defining, a pointer to struct node, is
that correct?
No. You are declaring a pointer, allocating space on the stack for the pointer, and dynamically allocating storage for a node to it it.
Don't confuse yourself by writing stuff like this:
typedef struct node
{
int data;
node * next;
} *head;
The way to write the struct in C++ is:
struct node
{
int data;
node * next;
};
You can now create a pointer:
node * pnode;
which allocates storage for the pointer.
and you can dynamically allocate storage for a node, and make the pointer point to it:
pnode = new node;
or do it all in one:
node * pnode = new node;
Now when you say:
pnode->data = 10;
you are not allocating anything. You are assigning 10 to the member called data of the node instance pointed to by pnode. Of course, if you had given your node a constructor (which you should normally do), you could do it all in one:
struct node
{
int data;
node * next;
node( int n, node * np ) : data( n ), next( np ) {}
};
node * pnode = new node( 10, 0 );

When you define your struct as you did and call new like you did, what you're doing is:
allocate a new struct node on the heap.
allocate space on the stack for newItem and set its value to the address of the new struct you allocated.
You didn't set any values to any of the members of the new struct. If you want that to happen whenever you create a new instance of the struct, you need to define a constructor.

typedef struct node
{
int data;
node *node;
} *head;
This declares node as a struct and defines head as a synonym for node*, so head is a type and not an object.
This makes this illegal: temp = head->next; because -> is not something that you can apply to a type.
new node dynamically allocates a node object and returns a pointer to it. node *newItem = new node; assigns this pointer to newItem. Note, though, that newItem->node (node here is a pointer object and not the type node) is not initialized so is neither null nor points to a valid node object.
This is also illegal because node has no next member.
newItem->next = temp;
I suggest that you choose a naming convention that means that you keep your types and your variables separate. It is somewhat confusing.

node *newItem = new node;
You create:
a new node on the heap (which in your case contains uninitialized values because you omitted the ()
a pointer on the stack, which points to this new node.
newItem->data = 100
simply sets the data member of the newly allocated node to 100.

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.

what is the asterisk in front of a variable used for in c++?

I am currently learning linked list and my prof sent us a code which is so hard to understand for me. I know that asterisk is used before the varaible to make it as a pointer but this one is infront of a variable.
Here is the code:
#include <iostream>
using namespace std;
struct Node {
int data;
struct Node *next;
};
struct Node *head = NULL;
void insert(int new_data) {
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = head;
head = new_node;
}
void display() {
struct Node* ptr;
ptr = head;
while (ptr != NULL) {
cout<< ptr->data <<" ";
ptr = ptr->next;
}
}
int main() {
insert(3);
insert(1);
insert(7);
insert(2);
insert(9);
cout<<"The linked list is: ";
display();
return 0;
}
This is the one that I am talking about:
void insert(int new_data) {
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = head;
head = new_node;
}
I dont know what is the purpose of the asterisk in here (struct Node*) malloc(sizeof(struct Node));\
and can someone tell me what is the purpose of malloc here malloc(sizeof(struct Node))
This asterisk is after the type name. It means "pointer to that type", in this case, pointer to struct Node.
Let's see this line of code as a whole: struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
Here, a variable new_node is declared, it has the type "pointer to struct Node". The function malloc allocates a piece of memory and returns a pointer to it. However, it doesn't know the type of the pointer, so it returns it as void* (pointer to something unknown).
That's why you need to cast it to the right type before assignment. (struct Node*) is a cast expression, it changes the type of the pointer to the "pointer to struct Node".
To sum up, this line of code allocates a piece of memory to store struct Node in it and saves its address in new_node variable.
But yes, as others have noted, it's not C++ code, it's C code.
In this case the "(struct Node*)" part means it is a struct pointer, in this case the Node struct, it means that it is pointing to the struct, in this case since it is a linked list, you'll have a bunch of this Node Structs all pointing to the "next" one until it reaches the head of the list which is
"struct Node *head = NULL; " then in this function
Then you use this function
void insert(int new_data) {
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));
new_node->data = new_data;
new_node->next = head;
head = new_node;
}
What it does is create a new Node and point it to the previous created Node, it would look something like this:
head<-Node1<-Node2<-Node3...
and can someone tell me what is the purpose of malloc here malloc(sizeof(struct Node))
Malloc here just tells the compiler to allocate the amount of memory the size of the struct called Node so that it doesn't use anymore or anyless then needed.
Also I think this is C not C++
https://www.programiz.com/cpp-programming/library-function/cstdlib/malloc
In the above code you posted, you are declaring data type of "struct Node" .
If you want to declare integer pointer you will do as below :
int *iPtr;
Similarly, here you are declaring pointer to data type struct Node, so it will be
struct Node *new_node;
I guess you got confused between data type and variable . Here "struct Node" is an user defined data type and "next", "head" and "new_node" are variable names.
And regarding malloc, malloc() is a function that will allocate memory in heap for the size of the data type you want and here you want to allocate memory for sizeof(struct Node) which is a size of one Linked list node.
And the malloc() function allocates sizeof(struct Node) bytes and returns a void pointer to the allocated memory and since malloc returns a void pointer (generic pointer) you have to typecast it to which ever data type you are allocating for.
Again I will give you simple example :
int *iPtr = (int *)malloc(sizeof(int));
Similarly, here for data type Struct Node it is done as below:
struct Node* new_node = (struct Node*) malloc(sizeof(struct Node));

About Create NODE using cpp

Hi every body i have some question:
struct NODE{
TYPEDATA data;
NODE *link;
};
NODE* CreateNODE(TYPEDATA n){ //1
struct NODE *node = new NODE; //2
if(node){
node->data=n;
node->link=NULL;
}
return node;
}
1.why i must have * after NODE for CreateNODE
2.why must use new NODE
thank you
By using new, you dynamically allocate memory for a node. New returns a pointer to the allocated memory. You indicate that a variable is a pointer by using * . Since you want to return that new node, you need to return not a NODE, but a pointer to NODE, thus effectively the return type becomes NODE* . If you don't know how pointers or dynamic memory work, I suggest you look at these links:
pointers
dynamic memory

error about a node in C++

I got this error and I dont know how to fix it.
error: must use 'struct' tag to refer to type 'node' in this scope
node *node = new node;
my code where the error is.
//New empty tree
struct node *newTreeNode(int data)
{
//New tree nodes
node *node = new node;
//New data node
node->data = data;
//New left node
node->left = nullptr;
//New right node
node->right = nullptr;
return node;
}
^
This error comes from the strangeness that is declaring an object with the same name as its type:
node *node = new node;
Not only is this extremely confusing to readers of your program, but now on the RHS the word node means the object, not the type. So new node becomes invalid.
The error message is kindly informing you that you can make node refer to the type by writing struct before it:
node* node = new struct node;
This works because, when T is a class type, struct T always means that class type T and cannot mean anything else.
But, honestly, simply do not do this. Use better names.
You have declared a variable called node. That is the name of a type you're intending to use after that declaration. So you need to specify that you're referring to the type, not the variable by using struct or class appropriately.
node *node = new struct node;
^^^^^^
The better solution would be to use a different name for the variable.
node* n = new node;

C++ function using reference as param error

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.