class Node{
public:
int data;
Node* next;
Node(int data)
{
this->data = data;
this->next = NULL;
}
};
int main()
{
Node* node1 = new Node(12);
cout<< node1->data ;
return 0;
}
Can't understand that why are we creating pointer object for the node (Node* node1)?
Thanks for clearing my doubt in advance
The code in main() needs a pointer simply because that is what new returns. The code is creating the Node object in dynamic memory on the heap (and consequently leaking it, since there is no delete node1; statement before the return statement).
You could instead create the object in automatic memory on the stack, and thus not need a pointer, eg:
int main()
{
Node node1(12);
cout << node1.data;
return 0;
}
Typically, linked lists are created using dynamic memory so that new nodes can be added to the list dynamically, such as in a loop, or in response to user input, etc.
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.
This question already has answers here:
Can a local variable's memory be accessed outside its scope?
(20 answers)
Passing pointer to local variable to function: is it safe?
(6 answers)
Closed 3 years ago.
I encounter a strange issue when using class in C++.
Here is my code to add object the my linked list. I found that my V1 code works correct but V2 code doesn't and the printList can never stop in V2. Do anyone can explain why it is the case, since I expect V1 and V2 code should output the same outcome.
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node *next;
Node() {
cout << "Node object is being created" << endl;
}
};
void printList(Node *node) {
while(node != NULL) {
cout << node->data << ",";
node = node->next;
}
cout << endl;
}
void push(Node **node, int data) {
// // working V1 start
// Node *newNode = new Node();
// newNode->data = data;
// newNode->next = *node;
// *node = newNode;
// // working V1 end
// not working V2 start
Node newNode;
newNode.data = data;
newNode.next = *node;
*node = &newNode;
// not working V2 end
}
int main() {
Node *a = NULL;
push(&a, 15);
push(&a, 10);
printList(a);
}
Your V2 stores a pointer to a node in automatic storage. That node is automatically destroyed at the end of the push function at which point the pointer is left dangling and no longer points to a valid object.
When you later attempt to indirect through that pointer, the behaviour of the program is undefined.
V1 does not have this problem, since it allocates the nodes in dynamic storage. Instead, the problem with V1 is that it leaks the allocated memory. Dynamic allocations created with new-expression need to be deallocated with delete-expression.
The second code snippet has undefined behaviour because 1) the pointer newNode is not initialized and 2) you did not allocate memory where you are going to store values data and *node.
Node newNode;
newNode.data = data;
newNode.next = *node;
In the first code snippet a memory for the new node is allocated and the pointer is initialized by the address of the allocated memory
Node *newNode = new Node();
So these statements
newNode.data = data;
newNode.next = *node;
are valid and write data to the allocated memory.
Take into account that if to define the class the following way (removing the default constructor)
class Node {
public:
int data;
Node *next;
};
then the function can be written much simpler
void push( Node **node, int data )
{
*node = new Node { data, *node };
}
I started writing a binary tree and then came up with this example and I'm not sure what's going on. So here's the code:
#include<iostream>
using namespace std;
struct Node
{
Node *left, *right;
int key;
Node()
{
left = NULL;
right = NULL;
key = 0;
}
Node(int key)
{
left = NULL;
right = NULL;
key = key;
}
};
struct Tree
{
Node* root;
void Add(int k)
{
Node* t;
t->key = k;
root->left = t;
}
Tree(int key)
{
this->root = new Node(key);
}
};
int main()
{
Tree* tree = new Tree(5);
tree->Add(4);
cout<<tree->root->left->key;
return 0;
}
Add function Add in Tree is whats confuses me. So, there is a pointer to Node object, but new keyword is not used and it appears to me that anyway there is memory allocated in the heap because I can reach the object. Shouldn't go out of scope and be destroyed? And why I can reach that object and print out its key?
Probably that memory belongs to your program and nothing bad seems to happen because you are using so little memory. If you use more memory, some object will own that unallocated space and expect it to remain unmodified. Then this code will start giving you problems.
You are "dereferencing an uninitilized pointer". There are questions relating to this here and here, for instance. Your compiler may blow up if you do this, or it may not: the behaviour is undefined. Anything might happen, including the appearance that things are working.
Use new, like you should.
This line …
Node* t;
… is like:
Node* t = random_address;
It means that the next line …
t->key = k;
… is able to corrupt interesting memory locations.
The code is invalid. In this function
void Add(int k)
{
Node* t;
t->key = k;
root->left = t;
}
local variable t is not initialized and has indeterminate value. So the execution of the statement
t->key = k;
results in undefined behaviour.
You correctly pointed to that there must be used operator new. For example
Node* t = new Node( k );
Nevertheless even in this case the function is invalid because it has to check whether the new key is less of greater than the key of root. Depending on the condition there should be either
root->left = t;
or
root->right = t;
The compiler throws runtime segfault upon following code :
#include <iostream>
#include <string>
using namespace std;
struct Node{
int data;
void *next;
string nodeType;
};
Node* initNode(int data){
Node *n = (Node*)malloc(sizeof(Node));
n->data = data;
n->next = NULL;
n->nodeType = "Node"; //if this line is commented it works else segfault
return n;
}
int main() {
Node *n1 = initNode(10);
cout << n1->data << endl;
}
Can someone please explain why string assignment does not work inside a struct which is dynamically allocated where in case of static allocation why it works ?
where as the following way it works :
Node initNode(string data){
Node n;
n.data = data; //This works for node creation statically
n.next = NULL;
n.nodeType = "Node"; //and even this works for node creation statically
return n;
}
and then in the main function:
int main() {
Node n2 = initNode("Hello");
cout << n2.data << endl;
}
This doesn't work because you don't actually construct a Node instance into the memory which you malloc.
You should use new instead:
Node *n = new Node{};
malloc only allocates memory, it has no idea what a class is or how to instantiate one. You should generally not use it in C++.
new allocates memory and constructs an instance of the class.
There is no place, where std::string constructor is executed.
You should use new
example *e = new example;
or placement new
void *example_raw = malloc(sizeof(example));
example *e = new(example_raw) example;
Node *n = (Node*)malloc(sizeof(Node));
This cast is nonsense. You can't just tell the compiler to pretend that a chunk of data you just allocate contains a valid Node object and then manipulate it.
string in c++ is an class and to create string objects use new instead of malloc as below .
Node *n = new Node{};
I'm attempting to craft my own basic singly linked list in C++ as a learning exercise, and I'm encountering some difficulty in the memory management department. As it stands I have...
A 'Node' class:
class Node
{
public:
char *value;
Node *next;
Node();
~Node();
};
Node::Node()
{
}
Node::~Node()
{
delete[] value;
}
And then my list (I've omitted certain method calls for brevity):
class LinkedList
{
private:
Node *head;
public:
LinkedList();
~LinkedList();
void Add(char **x);
};
LinkedList::LinkedList()
{
head = 0;
}
LinkedList::~LinkedList()
{
Node *temp;
Node *current = head;
while(current)
{
temp = current;
current = current->next;
delete temp;
}
}
void LinkedList::Add(char **x)
{
Node *nodeToAdd = new Node();
nodeToAdd->value = *x;
nodeToAdd->next = NULL;
Node *current = head;
if(!head)
{
head = nodeToAdd;
return;
}
while(current->next)
{
current = current->next;
}
current->next = nodeToAdd;
}
I'm attempting to use this code as follows (again I've omitted things for brevity):
int main()
{
LinkedList *list = new LinkedList();
char *alpha = "alpha";
char *beta = "beta";
char *charlie = "charlie";
char *delta = "delta";
char *echo = "echo";
list->Add(&alpha);
list->Add(&beta);
list->Add(&charlie);
list->Add(&delta);
list->Add(&echo);
delete list;
}
The last call in main to delete the list produces an error:
Debug Assertion Failed! Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)
What am I doing wrong here?
The data pointed to by the various Node::value aren't dynamically allocated, so you shouldn't delete them. Applying the concept of "ownership", nodes should either make their own copies of data, which they own and can delete, or nodes don't own data, so they shouldn't be responsible for deleting it.
You can also implement multiple ownership using reference counting, like Objective-C does (see Objective-C Memory Management Rules for more info) but you have to be careful to avoid ownership cycles. You often find some type of reference counting in third-party smart pointers, such as Boost's smart_ptr library. Since you're doing this for the learning experience, it may make more sense to roll your own than use a library. Of course, you could also use a library for now, letting you focus on whatever you're trying to learn.
One day a student came to Moon and said: “I understand how to make a better garbage collector. We must keep a reference count of the pointers to each cons.”
Moon patiently told the student the following story:
“One day a student came to Moon and said: ‘I understand how to make a better garbage collector...
you are trying to release the memory which is not allocated on heap.
char *alpha = "alpha"; --- not allocated on heap
calling delete[]in Node destructor would lead to heap corruption.
Some points:
1) initialize pointers properly in the constructor:
Node::Node():value(NULL),next(NULL)
{
}
2) Take a ownership of value.
Allocate the memory on heap and copy
the contents
You shouldn't release a pointer use delete[]/delete if it's not created by new operator. There are some actions under the hood for the delete[] operation, like releasing/reclaiming marked memory from a managed pool. Since your pointer doesn't belong to these stuff, there will be a problem. IMHO, the underlying delete[] code is the _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) stuff.
The problem is that you're assuming that you can delete the data inside node, but you're passing in pointers to string literals instead, which you can't delete.
If you're assuming that the Node object controls the lifetime of the data inside it, your Node constructor or the Add function in LinkedList will have to make a copy of the data that it is being passed.
In your destructor, you are trying to array delete (delete [ ]) a static string. You have change your Add function to reserve the string and copy it first. See the code below.
However, if I were you and fairly new to memory management, I'd really use something like CString instead of a raw "char *" as it's much easier to deal with.
void LinkedList::Add(const char *x)
{
Node *nodeToAdd = new Node();
int len=strlen(x);
nodeToAdd->value = new char [len+1]; // room for string + terminating 0
strcpy(nodeToAdd->value,x);
nodeToAdd->next = NULL;
Node *current = head;
if(!head)
{
head = nodeToAdd;
return;
}
while(current->next)
{
current = current->next;
}
current->next = nodeToAdd;
}
value and next in Node class doesn't have memory allocated. You should allocate memory in Node's constructor.