Delete Pointer in C++ got me confused - c++

**struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
};
ListNode* Merge(ListNode* list1, ListNode* list2){//list1 2; list2 4
ListNode* result = new ListNode(0);
ListNode* travel = result;
while(list1 || list2){
cout << "hereWhile" << endl;
//cout << list1->val << list2->val << endl;
if(!list1){
travel->val = list2->val;
list2 = list2->next;
travel->next = new ListNode(0);
travel = travel->next;
}
else if(!list2){
travel->val = list1->val;
list1 = list1->next;
travel->next = new ListNode(0);
travel = travel->next;
}
else{
if(list1->val <= list2->val){
travel->next = new ListNode(0);
travel->val = list1->val;
list1 = list1->next;
travel = travel->next;
}
else{
travel->next = new ListNode(0);
travel->val = list2->val;
list2 = list2->next;
travel = travel->next;
}
}
}
cout << "travel at the end: " << (travel == result->next->next) << endl;
delete result->next->next;
//delete travel;
cout << travel->val << endl;
cout << result->val << endl;
cout << result->next->val << endl;
cout << "val: " << result->next->next->val << " end" << endl;
return NULL;
}**
in my case, the above delete method never works.
I have updated my whole code in order to provide more details. This is part of implementing a MergeSort by linked list. And my testcase is this recursion and this Merge function is list1 = {2} and list2 = {4} , so the Merge function is designed to return the head of a linked list {2,4} which has a size of two nodes.
In my code above, I declared a new node to travel->next in each of my if statement and I move travel one step further. Hence after the while loop, my linked list becomes {2,4,0} and I have a pointer "travel" pointing to ListNode{0}. However, it cannot be deleted! I have tried both by "delete result->next->next" and "delete travel" but it can still return result->next->next->val, which is 0! (my last cout statement)
WHY?
I declared this new ListNode (which is a struct) in my heap memory. And I want to delete this ListNode out of the while loop. But my delete never works. Maybe the travel was in heap in the brackets, but came out as stack memory after the while loop because I declare the dynamic memory in my loop?

use this in the loop to prevent memory leak
<pointer to struct for list2> tmp1 = list2;
list2 = list2->next;
delete tmp1;
<pointer to struct for travel> tmp2 = travel; travel = travel->next;
delete tmp2;

I have some questions.
Do you want to remove the whole list of travel or a single node?
What is the initialize value for travel?
you are checking the list1, but not using it inside the loop. Give more details about it.
I assume you need to delete the whole list of travel (list1), and travel is iterator of list1.
travel = list1;
while(list1 != NULL)
{
list1 = list1->next;
delete travel;
travel = list1->next;
}

Related

Unexpected return value from main() function

I am working with doubly linked list. Every function operates well but at the end of main(), it stalls few seconds and return an unexpected random value.
At first I thought it was caused by the report() function, thus I put one more add() function at the end but nothing got fixed. I doubt it is a memory deallocating problem, but I don't see where some object got pre-deallocated.
(Compiled using Code::Blocks 17.12).
Here is my .cpp file (all in one):
#include <iostream>
using namespace std;
typedef struct element {
element(){
data = 0;
next = 0;
prev = 0;
}
~element(){
delete next;
delete prev;
cout << "element destructed" << endl;
}
int data;
element* next;
element* prev;
} elem;
typedef struct doublylinkedlist{
doublylinkedlist(){
head = 0; tail = 0;
}
~doublylinkedlist(){
while(head!=0) {
head = head->next;
delete head->prev;
}
delete tail;
cout << "list destructed" << endl;
}
elem* head;
elem* tail;
} doublyll;
doublyll ls;
void add(){
elem* temp = new elem;
cout << "Enter an integer: ";
cin >> temp->data;
if(ls.head == 0) {//empty
ls.head = new elem;
ls.head = temp;
} else{
if(ls.tail == 0){ //1-item list
ls.tail = new elem;
ls.tail = temp;
ls.head->next = ls.tail;
ls.tail->prev = ls.head;
}
else{
temp->prev = ls.tail;
ls.tail->next = temp;
ls.tail = temp;
}
}
}
void report(){
if(ls.head == 0) cout << "List is empty!" << endl;
else{
elem *temp = ls.head;
do{
cout << temp->data << endl;
temp = temp->next;
} while (temp != 0);
}
}
int main(){
report();
add();
add();
add();
report();
add();
return 0;
}
Could someone point out where the error comes from and how to fix it? I want the main() not to stall and return 0 as usual, not to the opposite.
This is the program when executed, this is my build message
First point: The elements will be deallocated by the class doublylinkedlist, so deallocating elements in the class element will cause double-deallocation.
Therefore, you should remove two delete statements from the destructior of the lass element.
~element(){
/* remove them */
//delete next;
//delete prev;
cout << "element destructed" << endl;
}
Second point: In the destructor of doublylinkedlist, head->prev is read after head = head->next; without checking if head is NULL.
head can be NULL by the assignment, so it should be checked.
~doublylinkedlist(){
while(head!=0) {
head = head->next;
if (head!=0) /* add this */
delete head->prev;
}
delete tail;
cout << "list destructed" << endl;
}
The last element will be deallocated by delete tail;, so this code looks tricky but should be OK.
Extra point: These code segments
ls.head = new elem;
ls.head = temp;
and
ls.tail = new elem;
ls.tail = temp;
are causing memory leaks by allocating elements and throwing them right away.
You should remove the extra allocations.
/* remove this */
//ls.head = new elem;
ls.head = temp;
and
/* remove this */
//ls.tail = new elem;
ls.tail = temp;
Unless you are using std::shared_ptr or similar constructs each object needs to have one other object which is it's owner and is responsible for deallocating it. Your code needs to have clear semantics for transferring ownership (e.g. a function createNode() would expect its caller to destroy the node).
In your code nodes are both deleted by the list and by each element. This means everything gets deleted twice (or more). In your particular case this is the sequence of events on destruction of doublylinkedlist:
doublylinkedlist deletes its first element.
The destructor of the first element deletes its previous element, this is null so has no effect
The destructor of the first element deletes its next element (the second element).
The destructor of the second element deletes its previous element (the first element)
The destructor of the first element deletes its previous element, this is null so has no effect
The destructor of the first element deletes its next element (the second element).
This infinite loop eventually causes a stack overflow. Note that this isn't guaranteed to be the exact sequence of events as deleting an object twice is undefined behaviour so potentially anything could happen.
The simple fix is to remove the element destructor and have the list be responsible for the lifetime of all elements.
You should also modify your doublylinkedlist destructor as it will attempt to dereference a null pointer on the last element, you also don't need to delete tail as it should have already been deleted. E.g:
~doublylinkedlist(){
while(head!=0) {
auto temp = head;
head = head->next;
delete temp;
}
}
You shoudl also make sure you obey the rule of three/five). One way of doing this is to make use of smart pointers, for example using unique_ptrs your code could look like this:
#include <iostream>
#include <memory>
using namespace std;
typedef struct element {
element() {
data = 0;
next = nullptr;
prev = nullptr;
}
~element() {
cout << "element destructed" << endl;
}
int data;
std::unique_ptr< element > next;
element* prev;
} elem;
typedef struct doublylinkedlist {
doublylinkedlist() {
head = 0; tail = 0;
}
~doublylinkedlist() {
std::cout << "list destructed\n";
}
std::unique_ptr< elem > head;
elem* tail;
} doublyll;
doublyll ls;
void add() {
std::unique_ptr<elem> temp(new elem());
cout << "Enter an integer: ";
cin >> temp->data;
if (ls.head == nullptr) {//empty
ls.head = std::move(temp);
}
else {
if (ls.tail == nullptr) { //1-item list
ls.head->next = std::move(temp);
ls.tail = ls.head->next.get();
ls.tail->prev = ls.head.get();
}
else {
temp->prev = ls.tail;
ls.tail->next = std::move(temp);
ls.tail = ls.tail->next.get();
}
}
}
void report() {
if (ls.head == 0) cout << "List is empty!" << endl;
else {
elem *temp = ls.head.get();
do {
cout << temp->data << endl;
temp = temp->next.get();
} while (temp != 0);
}
}
int main() {
report();
add();
add();
add();
report();
add();
return 0;
}
The ownership of elements is now explicit, the list owns head and head owns its next node which owns its next node etc. Destroying the list automatically destroys the first node which automatically destroys the second node etc. In this code you can actually omit the destructors completely. This should also help to prevent memory leaks, for example if you decide to add some error checking to add the unused temp element gets automatically deleted:
void add() {
std::unique_ptr<elem> temp(new elem());
cout << "Enter an integer: ";
cin >> temp->data;
if (!cin || temp->data > 100) {
cout << "invalid input value\n";
return; // temp is automatically deleted here
}
...
}

Copy a linked list to another linked list c++

I'm trying to copy 1 list to another, but it copies only the first element. When I debug it, it showed me the error on the highlighted line.
Can you help me to solve this error and explain to me what's going wrong?
struct List1 {
int data;
List* next;
};
struct List3 {
int data3;
List3* next3;
};
void copyList(){
if(p==NULL) cout<<"Lista este vida\n";
else
{
c=p;
List3* x = new List3;
while(c!=NULL)
{
***x->data3 = c->data;***
cout<<x->data3<<" ";
c=c->next;
x=x->next3;
}
}
cout <<"\nList has been copied successful\n";
}
You are allocating only 1 List3 node for your x list.
On the first loop iteration, x points to a valid List3 instance. But you are not initializing its next3 member. So on the next loop iteration, the value of x becomes indeterminate, it is not pointing at valid memory.
You need to allocate a separate node for every value that you want to copy. For example:
void copyList()
{
if (p == NULL)
cout << "Lista este vida\n";
else
{
List1 *c = p;
List3* x = NULL;
List3** px = &x;
do
{
*px = new List3;
(*px)->data3 = c->data;
(*px)->next3 = NULL;
cout << (*px)->data3 << " ";
px = &((*px)->next3);
c = c->next;
}
while (c != NULL);
// use x as needed. don't forget to delete all
// of the nodes when you are done using them!
cout << "\nList has been copied successful\n";
}
}

Inserting and finding nodes - Linked Lists in C++

1) I'm still trying to wrap my head around how linked lists work in c++. Currently I'm trying to insert a new node in between other nodes. Although I'm able to add the desired node, anything after that new node seems to be deleted once I print it:
void InsertNode(int pos, int val) {
Node *n = new Node();
n->data = val;
Node *pnt = head;
for (int i = 0; i < pos; i++) {
pnt = pnt->next;
}
pnt->next = n;
DisplayList();
}
2) And then I want to be able to create another operation that can search for an element in the list and output its position (if it exists). However from what I know so far I don't see how I can compare a value that I want to find to an element in a list.
Here's what I'd imagine it would look like, but I know the if statement isn't valid.
void SearchElement(int val) {
Node *list = head;
int i = 0;
while (list) {
list = list->next;
i++;
if (list == val) { cout << "The value is at position: " << i << endl; }
}
//print statement saying it doesn't exist
}
You have to append the rest of the list to n before you insert the new node:
n->next = pnt->next;
pnt->next = n;
For the second question: Your value is in list->data.
int i = 0;
while (list) {
if (list->data == val) {
cout << "The value is at position: " << i << endl;
break;
}
list = list->next;
i++;
}

How to display all list values without endless loop

I have a list and I want to display it's values.
I want to see 1 2 3 4, but I have a endless loop like 1 2 3 4 1 2 3 4 1 2..
Can't understand, why?
struct node
{
int item;
node *next;
node(int x, node *t)
{
item = x;
next = t;
}
};
int main()
{
node *firstElement = new node(1, NULL);
firstElement->next = firstElement;
node *lastElement = firstElement;
for (int i = 2; i < 5; i++)
lastElement = (lastElement->next = new node(i, firstElement));
for (node *first = lastElement; first != 0; first = first->next)
cout << first->item << " ";
delete firstElement;
return 0;
}
Try using this code:
struct node
{
int item;
node *next;
node(int x, node *t)
{
item = x;
next = t;
}
};
int main()
{
node *firstElement = new node(1, NULL);
node *lastElement = firstElement;
for (int i = 2; i < 5; i++)
lastElement = (lastElement->next = new node(i, nullptr));
for (node *first = firstElement; first != 0; first = first->next)
cout << first->item << " ";
return 0;
}
IdeOne live code
The problem is that you set the "next" link of your last node to this node itself, not nullptr.
Also, it's better to delete the memory allocated
The problem is that your data structure has an infinite loop in itself: this line
firstElement->next = firstElement;
makes firstElement point back to itself, creating a circular list. When you add more elements, your list remains circular, so exit condition first == 0 is never achieved.
If you want your list to remain linear, not circular, your insertion code should be modified as follows:
node *firstElement = new node(1, NULL);
node *lastElement = firstElement;
for (int i = 2; i < 5; i++) {
lastElement->next = new node(i, lastElement->next)
lastElement = lastElement->next;
}
The printing code should start with firstElement:
for (node *current = firstElement; current != 0; current = current->next)
cout << current->item << " ";
Finally, deleting a single firstItem is not sufficient. You need a loop to traverse the whole list. Alternatively, you could chain deletion in the destructor by calling delete next, but this is dangerous, because recursive invocation of destructors may overflow the stack.
You have a loop in your list, because lastElement->next always points to firstElement. This is why first will never be equal to 0.
If you really need a loop I think you should write something like this:
node* p = firstElement;
do {
cout << p->item << " ";
p = p->next;
} while (p != firstElement);
The problem is that you create every node with firstElement as its next.
This would make sense if you were adding nodes to the front of the list, but you're adding them at the back, so the last node will point back to the start.
Since you're adding to the back, terminate the list on every insertion instead:
lastElement->next = new node(i, nullptr))

C++ Linked List Sorting, Splitting, and Printing issue

Hi guys for my lab assignment this week I was assigned to learn about Linked Lists. The lab prompt is as follows:
Write a program that creates a forward linked list of at least 20 elements, where each element holds a random integer between 0 and 99. Print the list.
Write the function "returnMiddleList" to find the middle element of the linked list in one pass. Print the integer value of this element and the position of this element (starting at zero) in relation to the head (where the head = 0, the element pointed to by the head = 1, the element pointed to by the previous one = 2, etc).
Split the list in half at the middle element to create two entirely separate* linked lists of near equal size (+/- 1) and print the two lists. Modify the "returnMiddleList" function to accomplish this, returning the head of the second linked list and setting the link of the element pointing to that head to null. Then print the two sums of the integers stored in the elements of both lists.
Sort the two lists from least to greatest and print them out (printing at this step is optional depending on the sort approach taken). Then combine the two lists while sorting them again from least to greatest and print out the new list. (HINT: you can subdivide the lists further and sort them on a scale of one to two element lists before sorting and combining the first two unsorted lists. What is this sort called?)
I have got #1 and #2 working, but #3 and #4 is where the issue is beginning. When I split my link list into two lists and print the individual lists out, my first link list prints out 9 numbers when it should be printing out 10 (the 10th number somehow disappears?), but when I do the sum of the first list right after that, the number that has disappeared gets added in the sum! I do not know why it is disappearing, and this is one issue. Another issue is in the second list, a random "0" gets added to the list and one of the numbers is lost. My last issue is about #4 as the merge algorithm I have used does not seem to work (I am merging the list together while sorting them, but I am not using a recursion sort because we have not learned that yet). Any input and help would be greatly appreciated! Thanks!
#include <iostream>
#include <stdlib.h>
#include <time.h>
using namespace std;
struct nodeType {
int data;
nodeType *link;
};
void populateList(nodeType *head) {
// srand(time(NULL));
nodeType *temp;
nodeType *current = head;
for (int i = 0; i < 20; i++) {
temp = new nodeType;
current->data = rand() % 100;
current->link = temp;
current = temp;
}
temp->link = NULL;
}
void print(nodeType *head) {
int i = 1;
while (head->link != NULL) {
cout << "#" << i++ << ": " << head->data << endl;
head = head->link;
}
}
nodeType* returnMiddleList(nodeType *head) {
nodeType *p1 = head, *p2 = head;
int count = 0;
int middle = 1;
while (p1->link->link != NULL) {
p1 = p1->link;
count++;
if (count % 2 == 0) {
p2 = p2->link;
middle++;
}
}
cout << "Middle #" << middle << ": " << p2->data << endl;
p1 = p2->link;
p2->link = NULL;
return p1;
}
void add(nodeType *head) {
int sum = 0;
while (head != NULL) {
sum = sum + head->data;
head = head->link;
}
cout << sum << endl;
}
void sort(nodeType *head) {
nodeType *temp = head;
while (temp != NULL) {
nodeType *temp2 = temp;
while (temp2 != NULL) {
if (temp->data > temp2->data) {
int temp3;
temp3 = temp->data;
temp->data = temp2->data;
temp2->data = temp3;
}
temp2 = temp2->link;
}
temp = temp->link;
}
}
nodeType* merge(nodeType* head1, nodeType* head2) {
nodeType *head3 = new nodeType, *current1 = head1, *current2 = head2;
while (current1 != NULL || current2 != NULL) {
if (current1 == NULL) {
while (current2 != NULL) {
//logic
current2 = current2->link; //dumps list 2
head3->data = current2->data;
}
break;
}
if (current2 == NULL) {
while (current1 != NULL) {
//Logic
current1 = current1->link; //dumps list 1
head3->data = current1->data;
}
break;
}
if (current1->data < current2->data) {
//logic
current1 = current1->link; //increments list 1
head3->data = current1->data;
} else {
//logic
current2 = current2->link; //increments list 2
head3->data = current2->data;
}
}
return head3;
}
int main() {
nodeType *head = new nodeType, *head2, *head3;
populateList(head);
print(head);
cout << endl;
head2 = returnMiddleList(head);
cout << endl << "List #1 Sum: ";
add(head);
cout << endl << "List #2 Sum: ";
add(head2);
sort(head);
cout << endl << "List #1 Sorted" << endl;
print(head);
sort(head2);
cout << endl << "List #2 Sorted" << endl;
print(head2);
head3 = merge(head, head2);
print(head3);
}
For #3, you don't need a count. The code should also include checks for head == NULL, p1 == NULL before attempting to check p1->link, and it should check for p1->link == NULL before attempting to check p1->link->link. After adding these checks, to eliminate the count, just advance p1 two at a time: p1 = p1->link->link, while advancing p2 one at a time: p2 = p2->link. Once you reach the end of the list with p1->link or p1->link->link, then consider p2 to be a pointer to the last node of the first half of the list, and follow the given instructions on how to split the list.
For #4, the approach of recursively splitting the list into sub-lists is generically known as a divide and conquer algorithm (wiki link). This approach is used for top down merge sort, and although there are other approaches which are better suited (faster) to implementing merge sort with linked lists, I get the sense that the instructor probably wants you to follow the given hints.