This is the revised version.
It takes 3.5GB memory and the pop function doesn't free the memory... How can I use new and delete to get those memory back? Now I'm using STL. since new and delete only works for pointers?
queue<Graphnode> ss;
for(i=0;i<30000000;i++)
{
ss.push( *g.root);
}
printf("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n");
for(i=0;i<30000000;i++)
{
ss.pop();
}
printf("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n");
//delete &ss;
here is my node.h file. I think I need to malloc and free or New, delete pointers here?
#include <stdio.h>
#include <stdlib.h>
#include <tr1/array>
typedef struct point
{
std::tr1::array<int, 16> state;
int x;
}point;
typedef struct Graphnode
{
struct point pvalue;
int depth;
struct Graphnode *up;
struct Graphnode *down;
struct Graphnode *left;
struct Graphnode *right;
}Graphnode;
so after revise the code should look like this?
#include <stdio.h>
#include <stdlib.h>
#include <tr1/array>
typedef struct point
{
std::tr1::array<int, 16> state;
int x;
int depth;
}point;
typedef struct Graphnode
{
point *pvalue = (point *)malloc(sizeof(point));
Graphnode *up = (Graphnode*)malloc(sizeof(Graphnode));
Graphnode *down= (Graphnode*)malloc(sizeof(Graphnode));;
Graphnode *left= (Graphnode*)malloc(sizeof(Graphnode));;
Graphnode *right= (Graphnode*)malloc(sizeof(Graphnode));;
}Graphnode;
If you're using c++, you should use queue<T> from the standard library. Here is a reference: http://www.cplusplus.com/reference/stl/queue/.
For c++ code you should never write your own container classes unless it is absolutely necessary. The standard library provides many useful containers that cover most use cases. They are heavily used and tested and have been for many years.
Your queue can clean up after itself if and only if struct Graphnode is self-contained and does not contain pointers to allocated memory.
void emptyQueue(struct queue *q) {
queueElement *element, *nextElement;
element = q->head;
while(element) {
nextElement = element->next;
free(element);
element = nextElement;
}
initQueue(q);
}
Note that since initQueue does not malloc, its counterpart function, emptyQueue, should not free. This allows you to create queues on the stack if you need to.
If your struct Graphnode has pointers to allocated memory, then you will need to do this by hand, and not in emptyQueue. Your code will look something like:
struct Graphnode node;
while(!isEmpty(q)) {
node = front(q);
/* Delete the stuff in `node` here. */
dequeue(q);
}
Some comments on your C code...
In enqueue you have:
if (q->head == NULL) {
//first element
q->head = newElement;
q->tail = newElement;
} else {
//put it to the tail
q->tail->next= newElement;
q->tail = newElement;
}
Since you're doing q->tail = newElement; in both paths, move it out:
if (q->head == NULL) {
//first element
q->head = newElement;
} else {
//put it at the tail
q->tail->next= newElement;
}
q->tail = newElement;
Also, consistent indentation is a good habit to have. Your text editor should make this easy for you.
In dequeue:
if (q->head == NULL) {
//empty queue
return;
} else {
element = q->head;
q->head = q->head->next;
free(element);
}
The else isn't needed, since the first part always returns.
if (q->head == NULL) {
//empty queue
return;
}
element = q->head;
q->head = q->head->next;
free(element);
Finally, in ifEmpty:
return (q->head == NULL ? 1:0);
C represents true as nonzero and false as 0. The result of the == operator is guaranteed to be like this, so there's no point forcing true to be 1;
return q->head == NULL;
One final note: on some systems, the "memory used" read out by a program like top might not go down. This is because the system is keeping the pages of freed memory around for future use. It may release the physical memory, but the virtual memory addresses will be kept around as "available" for your program until termination.
Even an empty queue structure will still use memory. I am assuming you have defined queue as something like
struct queue
{
queueElement* head;
queueElement* tail;
};
So an empty queue will still require the memory to store the head and tail pointers even when they are both NULL.
How are you "measuring" the memory usage? Obviously sizeof is no good as it'll just be the constant size of the struct queue. So I assume you've got some other tool or code which is measuring it. But the code looks OK to me, and shuld be releasing the memory as you expect.
One bug you have is that the dequeue function never sets tail. But if head is NULL after setting it to head->next, then you also need to set tail to NULL. Don't think this would cause a memory leak, but definitely opens you up to a corruption or segfault if you enqueue after a dequeue empties the queue.
Related
I would like to save (serialize) an MFC tree control in a dialog and recall it to populate the tree when the dialog is initialized. I thought the way to approach that task would be to first code a program that creates a (preferably) vector representation of the tree, stores it in a text file, and then recreates the tree representation by deserializing from the saved file. I would also prefer to save the nodes as CStrings because that’s how I’m used to saving and reading text from files. However, not only can I not get to first base on this, I can’t even pick up the bat. The following minimal code to create a single node using std::string runs ok.
#include <string>
#include <vector>
// A node of N-ary tree
struct Node {
std::string key;
std::vector<Node*> child; // An array of pointers for children
};
// A utility function to create a new N-ary tree node
Node* newNode(std::string key)
{
Node* temp = new Node;
temp->key = key;
return temp;
}
// A utility function to create a tree
Node* createTree()
{
Node* root = newNode( "Root" );
return root;
}
int main()
{
Node* root = createTree();
return 0;
}
But if I change it to use CString instead,
#include <afx.h>
#include <tchar.h>
#include <vector>
struct Node {
CString key;
std::vector<Node*> child; // An array of pointers for children
};
Node* newNode(CString key)
{
Node* temp = new Node;
temp->key = key;
return temp;
}
Node* createTree()
{
Node* root = newNode( _T("Root") );
return root;
}
…when the program exits it reports a memory leak. Could someone please explain why, and what if anything I can do to correct it?
As the previous answer and comments noted, someone has to free all allocated memory.
When you use new, the responsibility is on you.
However, C++ provides smart pointers that can manage memory allocation and freeing for you; please see https://en.cppreference.com/w/cpp/memory/unique_ptr.
Your sample code will look like this:
#include <atlstr.h>
#include <tchar.h>
#include <vector>
#include <memory>
struct Node {
CString key;
std::vector<std::unique_ptr<Node>> child;
};
std::unique_ptr<Node> newNode(CString key)
{
std::unique_ptr<Node> temp = std::make_unique<Node>();
temp->key = key;
return temp;
}
std::unique_ptr<Node> createTree()
{
std::unique_ptr<Node> root = newNode(_T("Root"));
root->child.push_back(newNode(_T("Child")));
return root;
}
APPENDED per question in the comment:
CString encode(std::unique_ptr<Node>& root)
{
if (root == nullptr)
return _T("");
{
CString sRep = root->key;
for (auto& temp : root->child)
sRep += encode(temp);
return sRep += _T("|");
}
}
It appears you have a memory leak in your original iteration as well (without using CString). You allocate memory on the heap for a new Node in newNode(std::string), but you never call delete on that pointer anywhere.
Simply delete root; somewhere before main() exits to fix this first memory leak.
Next, you'll find that once you populate the vector<Node*> child with pointers, those will need to be deleted somehow as well. I suggest adding a destructor to your struct Node that iterates through vector and explicitly calls delete on each pointer in there.
A note on CString
A quick search about how CString works[1] (because I've never dealt with it before) indicates that when you make a copy of a CString (such as by using the copy assignment operator), a new object isn't created, but a reference counter is incremented in the original CString object. The object is only destroyed once that reference counter reaches zero.
Since you're never calling delete on your Node pointer, the CString object in the Node object is never deleted, and this reference number is never decreased. Calling delete should fix the problem, but please report back whether or not it does.
How to deal with memory leaking with template classes in C++?
In this code I defined 4 template classes:
class node and class linked_list make up a doubly linked list
class item and class bag just make up another doubly linked list
These template classes are designed to deal with objects of various classes.
In the main function, I first created a linked_list<string> and a bag<int> and everything is fine.
But when I try to make a bag<linked_list<string>>, problems arise.
I tried to trace back to see what happened, and I saw that in the function push_back in class bag, a destructor of linked_list has been called that erased all the data in the input v. I don't know why that happens.
Note that I overwrote the destructors for all classes and called className.~className() in the main function to prevent memory leaking.
And it does work to prevent memory leaking from ls_1 and bag_1.
I don't know which part of my code is wrong. Can somebody help me?
#include <iostream>
#include <stdlib.h>
#include <string>
using namespace std;
//node and linked_list class make up a doubly linked list
template<class T> class node {
public:
T value;
node<T> * next;
node<T> * previous;
node<T>() { next = nullptr; previous = nullptr; }
node<T>(T v) { value = v; next = nullptr; previous = nullptr; }
~node<T>() { delete next; }
};
template<class T> class linked_list { //doubly linked list
public:
node<T> * head;
node<T> * tail;
linked_list<T>() { head = nullptr; tail = nullptr; }
~linked_list<T>() { delete head; }
void push_front(T v) { //insert an item to the front
node<T> * p = new node<T>(v);
p->next = head;
head = p;
if (tail == nullptr) {
tail = p;
}
}
};
//item and bag class just make up another doubly linked list
template<class X> class item {
public:
X value;
item<X> *next;
item<X> *previous;
item<X>(X v) { value = v; next = nullptr; previous = nullptr; }
~item<X>() { delete next; }
};
template<class X> class bag { //just another doubly linked list
public:
item<X> *last;
item<X> *first;
int num_items;
int size() { return num_items; }
bag() { last = nullptr; first = nullptr; num_items = 0; }
~bag() { delete first; }
void push_back(X v) { //insert an item to the back
item<X> * p = new item<X>(v);
if (num_items == 0) {
last = first = p;
}
else {
last->next = p;
p->previous = last;
last = p;
}
num_items++;
last->next = nullptr;
}
};
int main() {
//When using built-in classes (like strings) as input
//there's no problem at all
linked_list<string> ls_1;
ls_1.push_front("David");
ls_1.push_front("John");
bag<int> bag_1;
bag_1.push_back(1);
bag_1.push_back(2);
//Problems arise here when using user defined classes (linked_list) as input
//I traced back and found out that a destructor has been called
//that erases all the data in the input. Donno how that happens
bag<linked_list<string>> bag_string;
bag_string.push_back(ls_1);
//These lines are to prevent the memory leaking
//I overwrote destructors for linked_list and node class
//otherwise there's still memory leaking
ls_1.~linked_list();
bag_1.~bag();
bag_string.~bag();
_CrtDumpMemoryLeaks();
getchar();
getchar();
}
Implement node, linked_list, item, bag copy constructors and assignments or declare them as deleted. The default versions generated by the compiler do not do the deep copying and that leads to multiple deletes of same objects after they were copied.
Read the rule of three/five/zero for full details.
A bit off-topic, but making a list node delete its siblings is a classic gotcha: for a sufficiently long list it ends up calling ~node<T>() recursively until it exhausts the stack. And this is the reason node pointers cannot be smart-pointers.
A fix would be to have a default destructor for nodes and make the list destroy the nodes in a loop, rather than recursively.
You may also like to use the full list node as a head of the list that points to itself when empty. That removes that nullptr checking logic completely.
I tried to trace back to see what happened, and I saw that in the function push_back in class bag, a destructor of linked_list has been called that erased all the data in the input v
Yes, this happens because your bag::push_back() takes its argument by value. This means it creates a copy of the ls_1 you created in main. You have not specified how to "copy" a list, so the compiler generated this function (a copy constructor) automatically. It can do that because your linked_list only contains two pointers, so the compiler assumes (because you have not told it otherwise) that copying the pointers over is all that is necessary to generate a copy of a linked_list. Unfortunately, that is not correct.
You now have two lists that manage the same contents: The original ls_1 in main() and the function argument v in push_back() - they both contain the same pointers.
Then the same thing happens again in your item constructor: You make a local copy of the list that holds the same pointers as the first two.
You now have several list objects pointing to the same data. Each one will try to destroy the data once it dies. This results in undefined behavior.
To correct this, you need to figure out how copying of a list should work. This is (in part) what the rule linked in the other comment is about: If the destructor of your class is not trivial (i.e. the compiler-generated version would not be sufficient, most likely because you need to release a resource like allocated memory), you should/must always care about how to handle your class being copied around. The various mechanisms that may invoke copy-like behavior (assignment, copy constructor, plus move versions in newer C++) need to be specified (or forbidden) by you.
I'm creating something similar to structure list. At the beginning of main I declare a null pointer. Then I call insert() function a couple of times, passing reference to that pointer, to add new elements.
However, something seems to be wrong. I can't display the list's element, std::cout just breaks the program, even though it compiler without a warning.
#include <iostream>
struct node {
node *p, *left, *right;
int key;
};
void insert(node *&root, const int key)
{
node newElement = {};
newElement.key = key;
node *y = NULL;
std::cout << root->key; // this line
while(root)
{
if(key == root->key) exit(EXIT_FAILURE);
y = root;
root = (key < root->key) ? root->left : root->right;
}
newElement.p = y;
if(!y) root = &newElement;
else if(key < y->key) y->left = &newElement;
else y->right = &newElement;
}
int main()
{
node *root = NULL;
insert(root, 5);
std::cout << root->key; // works perfectly if I delete cout in insert()
insert(root, 2);
std::cout << root->key; // program breaks before this line
return 0;
}
As you can see, I create new structure element in insert function and save it inside the root pointer. In the first call, while loop isn't even initiated so it works, and I'm able to display root's element in the main function.
But in the second call, while loop already works, and I get the problem I described.
There's something wrong with root->key syntax because it doesn't work even if I place this in the first call.
What's wrong, and what's the reason?
Also, I've always seen inserting new list's elements through pointers like this:
node newElement = new node();
newElement->key = 5;
root->next = newElement;
Is this code equal to:
node newElement = {};
newElement.key = 5;
root->next = &newElement;
? It would be a bit cleaner, and there wouldn't be need to delete memory.
The problem is because you are passing a pointer to a local variable out of a function. Dereferencing such pointers is undefined behavior. You should allocate newElement with new.
This code
node newElement = {};
creates a local variable newElement. Once the function is over, the scope of newElement ends, and its memory gets destroyed. However, you are passing the pointer to that destroyed memory to outside the function. All references to that memory become invalid as soon as the function exits.
This code, on the other hand
node *newElement = new node(); // Don't forget the asterisk
allocates an object on free store. Such objects remain available until you delete them explicitly. That's why you can use them after the function creating them has exited. Of course since newElement is a pointer, you need to use -> to access its members.
The key thing you need to learn here is the difference between stack allocated objects and heap allocated objects. In your insert function your node newElement = {} is stack allocated, which means that its life time is determined by the enclosing scope. In this case that means that when the function exits your object is destroyed. That's not what you want. You want the root of your tree to stored in your node *root pointer. To do that you need to allocate memory from the heap. In C++ that is normally done with the new operator. That allows you to pass the pointer from one function to another without having its life time determined by the scope that it's in. This also means you need to be careful about managing the life time of heap allocated objects.
Well you have got one problem with your Also comment. The second may be cleaner but it is wrong. You have to new memory and delete it. Otherwise you end up with pointers to objects which no longer exist. That's exactly the problem that new solves.
Another problem
void insert(node *&root, const int key)
{
node newElement = {};
newElement.key = key;
node *y = NULL;
std::cout << root->key; // this line
On the first insert root is still NULL, so this code will crash the program.
It's already been explained that you would have to allocate objects dynamically (with new), however doing so is fraught with perils (memory leaks).
There are two (simple) solutions:
Have an ownership scheme.
Use an arena to put your nodes, and keep references to them.
1 Ownership scheme
In C and C++, there are two forms of obtaining memory where to store an object: automatic storage and dynamic storage. Automatic is what you use when you declare a variable within your function, for example, however such objects only live for the duration of the function (and thus you have issues when using them afterward because the memory is probably overwritten by something else). Therefore you often must use dynamic memory allocation.
The issue with dynamic memory allocation is that you have to explicitly give it back to the system, lest it leaks. In C this is pretty difficult and requires rigor. In C++ though it's made easier by the use of smart pointers. So let's use those!
struct Node {
Node(Node* p, int k): parent(p), key(k) {}
Node* parent;
std::unique_ptr<Node> left, right;
int key;
};
// Note: I added a *constructor* to the type to initialize `parent` and `key`
// without proper initialization they would have some garbage value.
Note the different declaration of parent and left ? A parent owns its children (unique_ptr) whereas a child just refers to its parent.
void insert(std::unique_ptr<Node>& root, const int key)
{
if (root.get() == nullptr) {
root.reset(new Node{nullptr, key});
return;
}
Node* parent = root.get();
Node* y = nullptr;
while(parent)
{
if(key == parent->key) exit(EXIT_FAILURE);
y = parent;
parent = (key < parent->key) ? parent->left.get() : parent->right.get();
}
if (key < y->key) { y->left.reset(new Node{y, key}); }
else { y->right.reset(new Node{y, key}); }
}
In case you don't know what unique_ptr is, the get() it just contains an object allocated with new and the get() method returns a pointer to that object. You can also reset its content (in which case it properly disposes of the object it already contained, if any).
I would note I am not too sure about your algorithm, but hey, it's yours :)
2 Arena
If this dealing with memory got your head all mushy, that's pretty normal at first, and that's why sometimes arenas might be easier to use. The idea of using an arena is pretty general; instead of bothering with memory ownership on a piece by piece basis you use "something" to hold onto the memory and then only manipulate references (or pointers) to the pieces. You just have to keep in mind that those references/pointers are only ever alive as long as the arena is.
struct Node {
Node(): parent(nullptr), left(nullptr), right(nullptr), key(0) {}
Node* parent;
Node* left;
Node* right;
int key;
};
void insert(std::list<Node>& arena, Node *&root, const int key)
{
arena.push_back(Node{}); // add a new node
Node& newElement = arena.back(); // get a reference to it.
newElement.key = key;
Node *y = NULL;
while(root)
{
if(key == root->key) exit(EXIT_FAILURE);
y = root;
root = (key < root->key) ? root->left : root->right;
}
newElement.p = y;
if(!y) root = &newElement;
else if(key < y->key) y->left = &newElement;
else y->right = &newElement;
}
Just remember two things:
as soon as your arena dies, all your references/pointers are pointing into the ether, and bad things happen should you try to use them
if you ever only push things into the arena, it'll grow until it consumes all available memory and your program crashes; at some point you need cleanup!
I'm reading the book Multithreading Applications in Win32
The book says return node->next will be compiled into separate machine instructions that would not be executed as an atomic operation, so Next() should also be protected by the critical section.
My question is, what instructions could it be translated into, to cause a race condition?
typedef struct _Node
{
struct Node *next;
int data;
} Node;
typedef struct _List
{
Node *head;
CRITICAL SECTION critical_sec;
} List;
List *CreateList()
{
List *pList = malloc(sizeof(List));
pList->head = NULL;
InitializeCriticalSection(&pList->critical_sec);
return pList;
}
void DeleteList(List *pList)
{
DeleteCriticalSection(&pList->critical_sec);
free(pList);
}
void AddHead(List *pList, Node *node)
{
EnterCriticalSection(&pList->critical_sec);
node->next = pList->head;
pList->head = node;
LeaveCriticalSection(&pList->critical_sec);
}
void Insert(List *pList, Node *afterNode, Node *newNode)
{
EnterCriticalSection(&pList->critical_sec);
if (afterNode == NULL)
{
AddHead(pList, newNode);
}
else
{
newNode->next = afterNode->next;
afterNode->next = newNode;
}
LeaveCriticalSection(&pList->critical_sec);
}
Node *Next(List *pList, Node *node)
{
Node* next;
EnterCriticalSection(&pList->critical_sec);
next = node->next;
LeaveCriticalSection(&pList->critical_sec);
return next;
}
Edit:
OK, although in this particular case it won't corrupt the singly linked list w/o protecting the Next() operation, a shared structure should be protected as a whole or nothing, generally.
return node->next performs two operations; it first loads the struct pointed to by node into memory, then looks at the node+offsetof(next) to find the pointer next, load that into a register, and then return to the calling program. The contents of node may be manipulated by another thread of execution in the meantime.
Yes, you absolutely need to protect your "next" with a lock in a multithreaded application.
... HOWEVER ...
"Writers" (like add or remove node) MUST be mutually exclusive. Critical section is a good choice.
"Readers" (like "next") can run concurrently with each other.
SUGGESTION:
If you can target Windows Vista or higher, consider using an SRW lock instead:
http://msdn.microsoft.com/en-us/library/aa904937%28VS.85%29.aspx
http://msdn.microsoft.com/en-us/magazine/cc163405.aspx
While I think the answer by sarnold is correct, I just wanted to point out that the sizeof() call in your malloc() call in CreateList appears to have a bug. I believe it should be:
List *pList = malloc(sizeof(List));
The way you had it, you will create enough memory to hold a pointer to a List and not the List structure. (You may also want to cast the return type to (List*) and compare it to NULL before using it..)
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.