Deleting nodes in a doubly linked list (C++) - c++

I have problems understanding why when I create two or more nodes (as shown below), the function void del_end()will only delete the char name[20] and not the whole node . How do I fix this problem without memory leak?
#include <iostream>
using namespace std;
struct node
{
char name[20];
char profession[20];
int age;
node *nxt;
node *prv;
};
node *start_ptr = NULL;
void del_end()
{
node *temp, *temp2;
temp = start_ptr;
if (start_ptr == NULL)
cout << "Can't delete: there are no nodes" << endl;
else if (start_ptr != NULL && start_ptr->nxt == NULL)
{start_ptr=NULL;}
else
{
while (temp->nxt != NULL)
{
temp = temp->nxt;
}
temp2=temp->prv;
delete temp;
temp->nxt= NULL;
}
}

Your code has some problems, the worst being here:
temp2=temp->prv;
delete temp2;
temp->nxt= NULL;
You're deleting the next-to-last node, leaving any pointers to it dangling, and losing the last node.
But if you post more of the real code, we can tell you more.
EDIT:
Here's a slightly cleaned-up version of del_end (and there's still plenty of room for improvement).
void del_end()
{
if (start_ptr == NULL)
{
cout << "Can't delete: there are no nodes" << endl;
return;
}
if (start_ptr->nxt == NULL)
{
delete start_ptr;
start_ptr = NULL;
return;
}
node *nextToLast = start_ptr;
node *last = start_ptr->nxt;
while(last->nxt != NULL)
{
nextToLast = last;
last = last->nxt;
}
delete last;
nextToLast->nxt = NULL;
return;
}
Note that this does not assume that the prev links are correct, which seems prudent here.

delete temp2;
WILL delete whole node.

The problem is that you appear to be trying to delete the last node, but you are in fact deleting the one right before it.
while (temp->nxt != NULL)
{
temp = temp->nxt;
}
temp2=temp->prv;
delete temp2;
temp->nxt= NULL;
This is your issue. Change it to this:
while (temp->nxt != NULL)
{
temp = temp->nxt;
}
temp2=temp->prv;
delete temp;
temp2->nxt= NULL;
And I believe it will work as intended. This saves off the next to last node, deletes the end and then sets the next to last node's nxt pointer to null, making it the last one.

If you're concerned about memory, I highly recommend learning to work with Valgrind http://valgrind.org/. It is a great tool. Valgrind divides memory leaks into 3 categories:
"definitely lost" - pointer to dynamically allocated memory is lost and there is no way to recover it
"possibly lost" - pointer to the dynamically allocated memory is pointing to the interior of a block and may be unrelated
"still reachable" - pointer to the dynamically allocated memory still exists, but the memory was never freed at the end of the programs execution
Running Valgrind is also very simple. Here's a link to the User Manual http://valgrind.org/docs/manual/manual.html. Some useful flags when running valgrind:
--leak-check=<no|summary|yes|full>
--show-reachable=<no|yes>
Now, the way I would remove a node in a doubly-linked list is:
// if the node to be removed is the head node
if (nodeToRemove->prev == NULL) {
// reassign the head node pointer
start_ptr = nodeToRemove->next;
} else {
// correct previous node pointer
nodeToRemove->prev->next = nodeToRemove->next;
}
// if the node to be removed node is the tail node
if (nodeToRemove->next == NULL) {
// reassign the tail node pointer
end_ptr = nodeToRemove->prev;
} else {
// correct next node pointer
nodeToRemove->next->prev = nodeToRemove->prev;
}
// deallocate memory
delete(nodeToRemove);
nodeToRemove = NULL;
Just declare node *end_ptr = NULL; after you declare start_ptr and when you append a node to the list, make sure the end_ptr is always pointing to the end of the list... and if you're adding to the end of the list, its easy... just point the end_ptr to the node being added.
You might as well keep a tail pointer, if you always have to delete the last node. So once you have the node you want to delete, I just check if its the head/tail node, reassign the next/prev pointers, and free the memory.
Btw... I took this from my C implementation, so if the syntax is off I apologize... but the logic is there.
Hope that helps.

Related

Improve my solution to basic C linked list management functions

I would appreciate some help relative to my code solution, which deals with linked list management in C. I'll already declare the only strange thing with my request: I am writing a C++ file, but I am actually mostly leveraging C resources (malloc(), free(), etc.); that said, given the basic code I provide, I am confident no one will have trouble with that.
I want to write a function to add elements to the end of the list and one to delete elements from it, that work in any edge case. Given my desire, the removal function was the one that I struggled the most with, but also the one that made me realize how little I am understanding pointers.
I will now share the code I produced, that should be working fine, but:
It can surely be greatly improved both in terms of clarity and performance
I think that showing it to the community will highlight many of the flaws present in my solution
// The plan is to create a linked list and to be able to add and delete its elements
#include <iostream>
using namespace std; // I can write output lines as cout << "Hi!", rather than std::cout < "Hi!"
#include <cstdlib> // needed for malloc() in C++
struct node {
int data;
node* nextPtr; //"struct node* nextPtr;" : This would be the syntax for plain old C: you always have to type the "struct" keyword
};
node* createElement(int data) {
node* newElemPtr = (node*)malloc(sizeof(node)); // the "(node*)" cast is required by C++, and is not used in C
newElemPtr->data = data;
newElemPtr->nextPtr = NULL;
return newElemPtr;
}
void appendElement(int data, node** head) { // Adds a new node at the end of the list
// I pass as argument a pointer to pointer (double pointer) to node, so that I can edit the head node
// if the list is empty, without having to return a new node pointer as head: my function indeed features
// "void" in its signature
node* elemPtr = NULL;
elemPtr = createElement(data); // elemPtr is a pointer to the new node
if (*head == NULL) {
*head = elemPtr;
}
else {
node* currPtr = *head; // currPtr is the temporary variable that visits each node of the linked list
while (currPtr->nextPtr != NULL)
currPtr = currPtr->nextPtr;
currPtr->nextPtr = elemPtr; // Set last element's nextPtr to "elem", i.e., a pointer to the new element
}
};
void removeElement(int data, node** head) { // Remove all the nodes whose data content matches the "data" argument
int presence_flag = 0; // Flag used to check whether the required data is present at all in the linked list
if (*head == NULL) {
return;
}
else {
node* currPtr = *head;
node* prevPtr = *head;
while (currPtr != NULL) {
// This is the case in which I find a node to delete (it matches the "data" query), and it is not the first of the list
if (data == currPtr->data && currPtr != *head) {
prevPtr->nextPtr = currPtr->nextPtr; // Link the node ahead of the one to delete with the one behind
free(currPtr);
currPtr = prevPtr; // In the next loop, I will resume the analysis from the previous node, which now points to an unvisited one
presence_flag = 1;
}
// This is the case in which I find a node to delete and it is the first of the list
else if (data == currPtr->data && currPtr == *head) {
// This is the case in which I have to delete the first node, but the list features other nodes
if (currPtr->nextPtr != NULL){
*head = currPtr->nextPtr; // Move *head forward
currPtr = *head; // Do the same with currPtr, in order not to break the while() loop
free(prevPtr); // As *head has already been re-assigned, I leverage prevPtr to delete the old *head
presence_flag = 1;
}
// This is the case in which I have to delete the first and only node of the list
else {
*head = NULL;
currPtr = *head;
presence_flag = 1;
}
}
// This is the case in which the current node does not match the queried "data" value
else{
prevPtr = currPtr; // Update prevPtr
currPtr = currPtr->nextPtr; // Move currPtr forward
}
}
}
if (presence_flag == 0)
cout << "There is not any node with value " << data << " in the linked list.\n\n";
// Q1: Am I causing any memory leak by using *head == NULL instead of free(*head)?
// Q2: Should I free() everythin before ending the main(), at least as a good practice?
// Q3: Is there a way to make this function by not using a double pointer as input and by also keeping "void" as return value?
// Of course, it should still work in the tricky edge case of the last element in the list that has to be deleted
};
void printLinkedList(node* head) { // Here I return nothing, so I can freely edit "head" (i.e., there is no need for a temporary pointer)
if (head == NULL) {
cout << "The linked list is empty.\n";
}
else {
int elemCounter = 0;
while (head != NULL) {
elemCounter += 1;
cout << "elem N. " << elemCounter << ": data value = " << head->data << "\n"; // head->data is equal to (*head).data
head = head->nextPtr;
}
}
};
int main(int argc, char* argv[])
{
//cout << "Size of a single node of the list = " << sizeof(node) << "\n";
// == 16. On a 64 bits machine, an int ("data") requires 4 bytes.
// The pointer requires 8 bytes; the remaining 4 bytes are padding
node* head = NULL;
appendElement(1, &head);
appendElement(2, &head);
appendElement(3, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 1...\n\n";
removeElement(1, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 2...\n\n";
removeElement(2, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 3...\n\n";
removeElement(3, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 4...\n\n";
removeElement(4, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 1...\n\n";
removeElement(1, &head);
printLinkedList(head);
cout << "\nRemoving element with data value = 2...\n\n";
removeElement(2, &head);
printLinkedList(head);
return 0;
}
As you can see from the comments embedded in the code, I have 3 doubts that captured my interest while coding the node removal function:
Q1: Am I causing any memory leak by using *head == NULL instead of free(*head)?
Q2: Should I free() everything before ending the main(), at least as a good practice?
Q3: Is there a way to make this function by not using a double pointer as input and by also keeping "void" as return value? Of course, it should still work in the tricky edge case of the last element in the list that has to be deleted
I hope that featuring these "additional" questions is something reasonable to put here, as maybe someone in the future may have the same doubts I had.
I know there are plenty of ready-to-copy-and-paste solutions for my task, but I think I can really learn this stuff if I see why my precise design choices are not optimal/wrong.
I thank everyone for the time spent reading this.
There are many duplicated code. Also the function should not output any message. It is the caller of the function that decides whether to output a message. So the function should have the return type bool if you are considering the program as a C++ program or bool or int if you are considering the program as a C program.
The function removeElement invokes undefined behavior because in its paths of execution you are not always resetting correctly values of the pointers currPtr and prevPtr after deleting a node.
For example after this code snippet
if (data == currPtr->data && currPtr != *head) {
prevPtr->nextPtr = currPtr->nextPtr; // Link the node ahead of the one to delete with the one behind
free(currPtr);
currPtr = prevPtr; // In the next loop, I will resume the analysis from the previous node, which now points to an unvisited one
presence_flag = 1;
}
prevPtr and currPtr will be equal each other.
I would define the function the following way
int removeElement( node **head, int data )
{
int deleted = 0;
while ( *head )
{
if ( ( *head )->data == data )
{
deleted = 1;
node *current = *head;
*head = ( *head )->next;
free( current );
}
else
{
head = &( *head )->next;
}
}
return deleted;
}
As for your question
Q3: Is there a way to make this function by not using a double pointer
as input and by also keeping "void" as return value? Of course, it
should still work in the tricky edge case of the last element in the
list that has to be deleted
then in C you can not achieve this. In C++ you can pass the pointer to the first node by reference. In C passing by reference means passing an object indirectly through a pointer to it. So in C you have to use a double pointer in such a case.
Of course just setting a pointer to NULL without freeing data pointed to by the pointer that was dynamically allocated produces a memory leak. And you should free all the allocated memory then it is not required any more.

Circular doubly linked list memory deallocation

I am having serious trouble cleaning up the memory of my circular linked list. I think I understand the issue though. My head pointer has, say, N allocations and my build pointer has N-1 allocations. The addback function can only have an integer and I can't use containers or vectors.
void Queue::addBack(int passed_Val)
{
if (head == nullptr) //takes care of first node when list is empty
{
head = new QueueNode;//head is my building now
cout<<"head is "<<sizeof(head)<<" bytes"<<endl;
head->val = passed_Val;
head->next = head;//this make an infinite loop
head->prev = head;
cout<<"node[0] mem allocated "<<head<<endl;
}
else
{
//build next will always have N-1 address, where N = number of addresses
//head points to. I don't want build to point to head when N=1
// have tempPtr point to old address
QueueNode* tempPrev = head->prev;//this will always point to the last node added!
QueueNode* build = new QueueNode;
build->next=head;
cout<<"build is "<<sizeof(build)<<" bytes"<<endl;
cout<<"node[1] mem allocated "<< build <<endl;
cout<<"node[1] "<< head <<endl;
build->val=passed_Val;
build->next = head;
head->prev = build;
tempPrev->next = build;
build->prev = tempPrev;
}
and my destructor looks like this
Queue::~Queue()
{
if(head !=nullptr)//needed because i don't want to deallocate head if it was never called
{
QueueNode* deletePtr = head->next;
cout<<"deallocating node[0] "<<head<<endl;
delete head;
while(deletePtr !=head)
{
delete deletePtr;
cout<<"deallocating pointer "<<deletePtr<<endl;
deletePtr =deletePtr->next;
}
}
}
I've thought about having the build pointer equal to the head pointer in the (head == nullptr) conditional but I am running into even more problems. Here is the result of my valgrind
I am thinking this line is my primary problem
==30923== Address 0x5a225e0 is 0 bytes inside a block of size 24 free'd
So if I understand correctly, I am trying to deallocate memory that has already been freed? How can I fix this in my destructor? I've tried messing around with my addback function but I end up losing nodes or more memory leaks :(
delete deletePtr;
This destroys whatever object deletePtr was referencing. Immediately afterwards:
deletePtr =deletePtr->next;
This attempts to reference deletePtr->next. As we've just determined, deletePtr's object has been destroyed, and dereferencing it becomes undefined behavior.
This may or may not be the only problem with the shown code. It's not possible to conclusively determine this without a minimum reproducible example, there may be other problems; but this is definitely one of them.
To add to the answer given by #SamVarshavchick, the code is flawed here:
delete head;
while(deletePtr != head) // <-- You are comparing deletePtr to a deleted pointer?
Given all that, the Queue destructor seems to bes more complex than it should be. The following is what I would have expected:
Queue::~Queue()
{
QueueNode* deletePtr = head;
QueueNode* nextPtr = nullptr;
while ( deletePtr )
{
nextPtr = deletePtr->next;
delete deletePtr;
deletePtr = nextPtr;
}
}
Note that there is no need to explicitly check for head being null at the beginning of the function, as the while loop will only be entered on a non-null value.
I was the destructor! Here is how I solved it
Queue::~Queue()
{
int i=1;
if(head !=nullptr)//needed because i don't want to deallocate head if it was never called
{
QueueNode* stop = head->prev;
QueueNode* deletePtr = head->next;//tractor node[1]
QueueNode* temp = head;// cutter node[0]
if(deletePtr ==head)// N=1
{
delete deletePtr;
}
else if(deletePtr == stop)//N=2
{
deletePtr = stop;
delete deletePtr;
delete head;
}
else//N >=3
{
while (temp != stop)//last node
{
delete temp; //delete node[0]
cout<<"temp "<<temp<<endl;
cout<<"deletePtr "<<deletePtr<<endl;
temp= deletePtr;// node[1]
deletePtr = deletePtr->next;//node[2]
cout<<"temp "<<temp<<endl;
cout<<"deletePtr "<<deletePtr<<endl;
}
delete stop;
}//end N>=3
}
}

how to search and delete a specific node in a linked list in c++ [duplicate]

I feel as if I am not actually deleting the node and freeing up memory. I think I am just moving pointers around so when I print the linked list the list doesn't print the element I deleted. So my question is am I actually deleting the node or am I just simply rearranging the pointers so it looks like I am deleting the nodes(Essentially just breaking the links but not deleting the node)? Thank you for any help.
void SLL::deleteNode(int target){
Node *current = new Node;
Node *previous = new Node;
for (current = front->next, previous = front; current != NULL; current = current->next, previous=previous->next){
if (previous->data == target && previous == front){
front = previous->next;
delete[] previous;
return;
//This if statement deletes the element if its the front
}
else {
if (previous->data == target && previous->next == NULL){
previous = NULL;
delete[] current;
return;
//This if statement deletes the node if it is the back
}
else if (current->data==target)
{
previous->next = current->next;
delete[] current;
return;
//This if statement deletes a node if it is in the middle
}
}
}
delete[] current;
delete[] previous;
}
Node *current = new Node;
Node *previous = new Node;
This code causes memory leaks - you are never deleting this memory. You can declare pointers without memory allocation:
Node *current = nullptr;
Node *previous = nullptr;
delete will delete the memory of the pointer so you will actually delete Nodes.
But using delete[] for the Node* is incorrect, it should be used only for arrays - the memory allocated with new[]. Improper use leads to undefined behaviour.
So, to properly delete nodes delete them with operator delete.
Use memory leaks detection tools to know are there memory leaks in you program.
The code to delete a list element: say, we have pHead which points to the head of the list
(but it would give you much more if you write such things yourself):
Node* pCur = pHead;
Node* pPrev = pCur;
while (pCur && pCur->data != target) {
pPrev = pCur;
pCur = pCur->next;
}
if (pCur==nullptr) // not found
return NOT_FOUND;
if (pCur == pHead) { // first element matches
pHead = pCur->next;
} else {
pPrev->next = pCur->next;
}
// pCur now is excluded from the list
delete pCur; // deallocate its memory
Alternative Using Pointer To Pointer (Community Addition)
The above can take on new light when you use the actual pointers in the list to perform the enumeration. The following starts with pp being assigned the address of the head pointer (not the node it points to; the actual pointer itself). We walk the list until pp hold the address of a pointer that is pointing to a node with the target to delete (could be the head pointer, could be a next pointer in some node, makes no difference). The pointer being addressed is set to its own node's next value, then the target node is removed.
This really should be watched in a debugger to see how it works, but the algorithm is remarkably simple given what is really going on:
Node **pp = &pHead;
while (*pp && (*pp)->data != target)
pp = &(*pp)->next;
if (*pp)
{
Node *victim = *pp;
*pp = victim->next;
delete victim;
}
Thats all of it. And you get head-node removal without having to special case it for free. Hope this helps as well.

How do I properly delete nodes of linked list in C++

I feel as if I am not actually deleting the node and freeing up memory. I think I am just moving pointers around so when I print the linked list the list doesn't print the element I deleted. So my question is am I actually deleting the node or am I just simply rearranging the pointers so it looks like I am deleting the nodes(Essentially just breaking the links but not deleting the node)? Thank you for any help.
void SLL::deleteNode(int target){
Node *current = new Node;
Node *previous = new Node;
for (current = front->next, previous = front; current != NULL; current = current->next, previous=previous->next){
if (previous->data == target && previous == front){
front = previous->next;
delete[] previous;
return;
//This if statement deletes the element if its the front
}
else {
if (previous->data == target && previous->next == NULL){
previous = NULL;
delete[] current;
return;
//This if statement deletes the node if it is the back
}
else if (current->data==target)
{
previous->next = current->next;
delete[] current;
return;
//This if statement deletes a node if it is in the middle
}
}
}
delete[] current;
delete[] previous;
}
Node *current = new Node;
Node *previous = new Node;
This code causes memory leaks - you are never deleting this memory. You can declare pointers without memory allocation:
Node *current = nullptr;
Node *previous = nullptr;
delete will delete the memory of the pointer so you will actually delete Nodes.
But using delete[] for the Node* is incorrect, it should be used only for arrays - the memory allocated with new[]. Improper use leads to undefined behaviour.
So, to properly delete nodes delete them with operator delete.
Use memory leaks detection tools to know are there memory leaks in you program.
The code to delete a list element: say, we have pHead which points to the head of the list
(but it would give you much more if you write such things yourself):
Node* pCur = pHead;
Node* pPrev = pCur;
while (pCur && pCur->data != target) {
pPrev = pCur;
pCur = pCur->next;
}
if (pCur==nullptr) // not found
return NOT_FOUND;
if (pCur == pHead) { // first element matches
pHead = pCur->next;
} else {
pPrev->next = pCur->next;
}
// pCur now is excluded from the list
delete pCur; // deallocate its memory
Alternative Using Pointer To Pointer (Community Addition)
The above can take on new light when you use the actual pointers in the list to perform the enumeration. The following starts with pp being assigned the address of the head pointer (not the node it points to; the actual pointer itself). We walk the list until pp hold the address of a pointer that is pointing to a node with the target to delete (could be the head pointer, could be a next pointer in some node, makes no difference). The pointer being addressed is set to its own node's next value, then the target node is removed.
This really should be watched in a debugger to see how it works, but the algorithm is remarkably simple given what is really going on:
Node **pp = &pHead;
while (*pp && (*pp)->data != target)
pp = &(*pp)->next;
if (*pp)
{
Node *victim = *pp;
*pp = victim->next;
delete victim;
}
Thats all of it. And you get head-node removal without having to special case it for free. Hope this helps as well.

Simple C++ Linked List

I have plenty of previous experience with linked lists in Java, but I seem to have confused myself with this simple attempt in C++. I am getting a segmentation fault at runtime, which from what I understand has to do with assigning a null pointer, but I am at a loss for a solution.
Edit: Thank you all for the very helpful responses. The code is now working, but trying to use delete p; at the end of linkedList::addNode results in a segmentation fault at runtime. Just curious if anyone knew why that is?
Here is my updated code:
#include <iostream>
using namespace std;
class Node{
public:
int data;
Node * next;
Node(int x){
data = x;
next = NULL;
}
Node(int x, Node * y){
data = x;
next = y;
}
};
class linkedList{
Node *head;
public:
linkedList(){
head = NULL;
}
void addNode(int value){
Node *p;
if(head == NULL)
head = new Node (value, NULL);
else{
p=head;
while(p->next !=NULL)
p=p->next;
p->next = new Node (value, NULL);
}
}
void print(){
Node * p;
p = head;
while(p != NULL){
cout << p->data << "\n";
p = p->next;
}
}
};
int main(void){
linkedList test;
test.addNode(4);
test.addNode(76);
test.addNode(12);
test.print();
return(0);
}
First, in linkedList::addNode method, you have the construction if (head = NULL), which will wind up assigning to head; you want the == operator.
Second, about the line:
head = &(Node (value, NULL));
For somewhat unintuitive reasons, this won't work. You'll get a reference to a Node, but that node will go out of scope as soon as the method ends, and attempts to reference it will lead to a segmentation fault. You need to use the new operator (same with the other similar line):
head = new Node(value, NULL);
If you add a method for removing a node, make sure to delete the node then—it won't get automatically garbage-collected like it will in Java.
Sidebar: Think of what happens like this: when you do Node(value, NULL), you're using a temporary variable that's declared like this:
Node hiddenTempNode(value, NULL);
This doesn't allocate space for an object anywhere except on the stack—it's very similar to allocating space for an int and a Node * on the stack as separate variables. As a result, as soon as you leave the method, the object disappears and the pointer to it will do weird things when used.
Third, beware: you may want to set next = NULL in your single-parameter constructor, to ensure that it always has a value. Similarly for your default constructor.
Fourth: your linkedList::print method is looping until p->next is NULL and printing the value of p->next; those occurrences of p->next should probably be changed to just p if you want to get the first and last items.
you are taking the address of variables on the stack
head = &(Node (value, NULL));
should be changed to
head = new Node(value, NULL);
same for the p->next code. Then you will want to delete these nodes in your destructor.
As for the printing try
while(p != NULL)
{
cout << p->data << "\n";
p = p->next;
}
You are allocating space for nodes on stack and grabbing its address, which will go away as soon as the block ends and consequently, the address will be rendered invalid. You should allocate nodes using new operator on the heap instead:
Node* node = new Node(value, NULL);
You should free everything you allocate on the heap as soon as you don't need it to prevent memory leak:
delete node;
For starters
if(head = NULL)
is an assignment, not a check for equality. Change it to
if(head == NULL)
Secondly,
head = &(Node (value, NULL));
Doesn't make sense* change this to
head = new Node (value, NULL);
*this actually creates a temporary object, gives you the address, then destroys that newly created object.
Thirdly,
Node(int x) { data = x; }
Leave next without a value, change this line to
Node(int x) { data = x; next = NULL; }
You are not allocating memory.You should use new to allocate it.
One more error in if(head = NULL) , it should be if(head == NULL)
void addNode(int value){
Node *p;
if(head == NULL)
head = new Node (value, NULL);
else{
p=head;
while(p->next !=NULL)
p=p->next;
p->next = new Node (value, NULL);
}
}
I'd like to add two issues that were not mentioned, yet:
when you 'new' objects, you must 'delete' them at some point.
all three of your constructors should initialize both member variables.
Your delete statement is not actually doing any cleanup. By the time you call it p==null. If you want to cleanup the list, you will need to implement a separate method to iterate through, and delete each and every node.
Something like this:
void ClearList ()
{
Node * c = head;
Node * n;
while (c != NULL)
{
n = c->next;
delete c;
c = n;
}
}
The code is now working, but trying to
use
delete p;
at the end of linkedList::addNode
results in a segmentation fault at
runtime. Just curious if anyone knew
why that is?
Well this is an issue because the purpose of the add node function was to dynamically allocate a new node at the end of the LinkedList. So you do that correctly, now by putting 'delete p;' you are deleting the newly added node (something I imagine you don't actually want). However, to answer your question which is why this causes a segmentation fault:
You add a node, you tell head to point to this new node. Now you delete this new node without telling head that it should once again point to NULL. Thus next time you add a node, or try to print your list, it will immediately attempt to look at what head is pointing to, which is in fact released (deleted) memory, kaboom?
The correct (or at least one correct) usage of delete in your list is in a destructor, remember in C++ we always want to clean up the dynamic memory that we have allocated, your destructor might look like:
~linkedList()
{
Node* p = head;
while ( p!=NULL )
{
Node* nextNode = p->next;
delete p;
p = nextNode;
}
}
By using a destructor like this you guarantee that your linkedList will be cleaned up appropriately when it goes out of scope, or is deleted.
Solution: Don't implement your own linked list. Use the one supplied by the standard library.