This question already has answers here:
Undefined, unspecified and implementation-defined behavior
(9 answers)
Closed 1 year ago.
The node Class is as follow:
class node
{
public:
int data; //the datum
node *next; //a pointer pointing to node data type
};
The PrintList Function is as follow:
void PrintList(node *n)
{ while (n != NULL)
{
cout << n->data << endl;
n = n->next;
}
}
If I try running it I get all three values (1,2,3) but I get an additional number as well which I'm unable to figure out what it represents, Can someone throw light on the same?
int main()
{
node first, second, third;
node *head = &first;
node *tail = &third;
first.data = 1;
first.next = &second;
second.data = 2;
second.next = &third;
third.data = 3;
PrintList(head);
}
I Know it can be fixed with
third.next = NULL;
But I am just curious what does this number represents in output, If I omit the above line
1
2
3
1963060099
As described in the comment by prapin, third.next is not initialized.
C++ has a zero-overhead rule.
Automatically initializing a variable would violate this rule as the value might be initialized (a second time) later on or never even be used.
The value of third.next is just the data that happened to live in the same memory location as third.next does now.
For this reason, it's recommended to always initialize your variables yourself.
It is better to initialize variables & it is better to use nullptr. Like that (See 1-3):
#include <iostream>
class node
{
public:
int data = 0; // 1
node* next = nullptr; // 2
};
void PrintList(node* n)
{
while (n != nullptr) // 3
{
std::cout << n->data << std::endl;
n = n->next;
}
}
int main()
{
node first, second, third;
node* head = &first;
node* tail = &third;
first.data = 1;
first.next = &second;
second.data = 2;
second.next = &third;
third.data = 3;
// third.next points to where?
PrintList(head);
}
Additional note:
I would prefer to use the STL container std::list:
#include <list>
#include <iostream>
std::list<int> int_list;
void PrintList()
{
for (auto i : int_list)
std::cout << i << std::endl;
}
int main()
{
int_list.push_back(1);
int_list.push_back(2);
int_list.push_back(3);
PrintList();
}
Or in case of list of node objects:
#include <list>
#include <iostream>
class node
{
public:
node(int data) : m_data{ data } {};
int m_data = 0;
// and maybe extra data-members
};
std::list<node> node_list;
void PrintList()
{
for (auto i : node_list)
std::cout << i.m_data << std::endl;
}
int main()
{
node_list.push_back(node(1));
node_list.push_back(node(2));
node_list.push_back(node(3));
PrintList();
}
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 9 months ago.
Improve this question
This is my C++ code:
#include <iostream>
using namespace std;
typedef struct Node
{
int data;
Node* next;
}Node;
class LinkedList
{
private:
Node* first;
Node* last;
public:
LinkedList() {first = last = NULL;};
LinkedList(int A[], int num);
~LinkedList();
void Display();
void Merge(LinkedList& b);
};
// Create Linked List using Array
LinkedList::LinkedList(int A[], int n)
{
Node* t = new Node;
if (t == NULL)
{
cout << "Failed allocating memory!" << endl;
exit(1);
}
t->data = A[0];
t->next = NULL;
first = last = t;
for (int i = 1; i < n; i++)
{
t = new Node;
if (t == NULL)
{
cout << "Failed allocating memory!" << endl;
exit(1);
}
t->data = A[i];
t->next = NULL;
last->next = t;
last = t;
}
}
// Deleting all Node in Linked List
LinkedList::~LinkedList()
{
Node* p = first;
Node* tmp;
while (p != NULL)
{
tmp = p;
p = p->next;
delete tmp;
}
}
// Displaying Linked List
void LinkedList::Display()
{
Node* tmp;
for (tmp = first; tmp != NULL; tmp = tmp->next)
cout << tmp->data << " ";
cout << endl;
}
// Merge two linked list
void LinkedList::Merge(LinkedList& b)
{
// Store first pointer of Second Linked List
Node* second = b.first;
Node* third = NULL, *tmp = NULL;
// We find first Node outside loop, smaller number, so Third pointer will store the first Node
// Then, we can only use tmp pointer for repeating process inside While loop
if (first->data < second->data)
{
third = tmp = first;
first = first->next;
tmp->next = NULL;
}
else
{
third = tmp = second;
second = second->next;
tmp->next = NULL;
}
// Use while loop for repeating process until First or Second hit NULL
while (first != NULL && second != NULL)
{
// If first Node data is smaller than second Node data
if (first->data < second->data)
{
tmp->next = first;
tmp = first;
first = first->next;
tmp->next = NULL;
}
// If first Node data is greater than second Node data
else
{
tmp->next = second;
tmp = second;
second = second->next;
tmp->next = NULL;
}
}
// Handle remaining Node that hasn't pointed by Last after while loop
if (first != NULL)
tmp->next = first;
else
tmp->next = second;
// Change first to what Third pointing at, which is First Node
first = third;
// Change last pointer from old first linked list to new last Node, after Merge
Node* p = first;
while (p->next != NULL)
{
p = p->next;
}
last = p;
// Destroy second linked list because every Node it's now connect with first linked list
// This also prevent from Double free()
b.last = NULL;
b.first = NULL;
}
int main()
{
int arr1[] = {4, 8, 12, 14, 15, 20, 26, 28, 30};
int arr2[] = {2, 6, 10, 16, 18, 22, 24};
int size1 = sizeof(arr1) / sizeof(arr1[0]);
int size2 = sizeof(arr2) / sizeof(arr2[0]);
LinkedList l1(arr1, size1);
LinkedList l2(arr2, size2);
l1.Display();
l2.Display();
// Merge two linked list, pass l2 as reference
l1.Merge(l2);
l1.Display();
return 0;
}
I'm beginner on C++ and in this code, I practice how to Merge two linked list. This actually works perfectly. I've successfully Merge the two Linked List in sorted order.
But, there's people said that I should've follow the Rule of Three on C++. Which implement: Destructor, Copy Constructor, and Copy Assignment Operator.
I've watched many videos about that. I do understand that is basically handle Shallow Copy especially when we don't want two different object point to the same address of memory. But, for my problem is, I still don't know how to Implement it on a Class that working on a Linked List just like my code above.
Someone said, in my main(), this code: l1.Merge(l2); is somehow incorrect because I don't have explicit Copy Constructor.
And if you look at my Merge() function, in Last line, if I didn't to this: b.last = NULL; and b.first = NULL; , which simply destroy pointer of Second Linked list, the Compiler give me warning: Double free() detected.
So, I think my question is:
How can this code: l1.Merge(l2); is have something to do with Copy Constructor?
Is Double free() happened because I don't implement the Rule of Three? If yes, how to address them?
How to write the Rule of Three based on my code? When or How to use them?
Based on this Code, is there something wrong? Do I still need the Rule of Three if my Program only want to Merge Linked List?
Thank You. I hope someone can explain to me like I'm 10 years old. and hope someone can write me some Code.
But, for my problem is, I still don't know how to Implement [Rule of Three] on a Class that working on a Linked List just like my code above.
You simply implement the copy constructor and copy assignment operator to iterate the input list, making a copy of each node and inserting them into your target list. You already have a working destructor. In the case of the copy assignment operator, you can usually use the copy-swap idiom to implement it using the copy constructor to avoid repeating yourself.
Someone said, in my main(), this code: l1.Merge(l2); is somehow incorrect because I don't have explicit Copy Constructor.
Then you were told wrong. Your Merge() code has nothing to do with a copy constructor.
And if you look at my Merge() function, in Last line, if I didn't to this: b.last = NULL; and b.first = NULL;, which simply destroy pointer of Second Linked list, the Compiler give me warning: Double free() detected.
Correct. Since you are moving the nodes from the input list to the target list, you need to reset the input list so it doesn't point at the moved nodes anymore. Otherwise, the destructor of the input list will try to free them, as will the destructor of the target list.
How can this code: l1.Merge(l2); is have something to do with Copy Constructor?
It doesn't have anything to do with it.
Is Double free() happened because I don't implement the Rule of Three?
Not in your particular example, as you are not performing any copy operations. But, in general, not implementing the Rule of Three can lead to double frees, yes.
How to write the Rule of Three based on my code?
See the code below.
Do I still need the Rule of Three if my Program only want to Merge Linked List?
No. Only when you want to make copies of lists.
With that said, here is an implementation that includes the Rule of Three:
#include <iostream>
#include <utility>
struct Node
{
int data;
Node *next;
};
class LinkedList
{
private:
Node *first;
Node *last;
public:
LinkedList();
LinkedList(const LinkedList &src);
LinkedList(int A[], int num);
~LinkedList();
LinkedList& operator=(const LinkedList &rhs);
void Display() const;
void Merge(LinkedList &b);
};
// Create Linked List using default values
LinkedList::LinkedList()
: first(NULL), last(NULL)
{
}
// Create Linked List using Array
LinkedList::LinkedList(int A[], int n)
: first(NULL), last(NULL)
{
Node **p = &first;
for (int i = 0; i < n; ++i)
{
Node *t = new Node;
t->data = A[i];
t->next = NULL;
*p = t;
p = &(t->next);
last = t;
}
}
// Create Linked List by copying another Linked List
LinkedList::LinkedList(const LinkedList &src)
: first(NULL), last(NULL)
{
Node **p = &first;
for (Node *tmp = src.first; tmp; tmp = tmp->next)
{
Node* t = new Node;
t->data = tmp->data;
t->next = NULL;
*p = t;
p = &(t->next);
last = t;
}
}
// Deleting all Node in Linked List
LinkedList::~LinkedList()
{
Node *p = first;
while (p)
{
Node *tmp = p;
p = p->next;
delete tmp;
}
}
// Update Linked List by copying another Linked List
LinkedList& LinkedList::operator=(const LinkedList &rhs)
{
if (&rhs != this)
{
LinkedList tmp(rhs);
std::swap(tmp.first, first);
std::swap(tmp.last, last);
}
return *this;
}
// Displaying Linked List
void LinkedList::Display() const
{
for (Node *tmp = first; tmp; tmp = tmp->next)
std::cout << tmp->data << " ";
std::cout << std::endl;
}
// Merge two linked list
void LinkedList::Merge(LinkedList& b)
{
if ((&b == this) || (!b.first))
return;
if (!first)
{
first = b.first; b.first = NULL;
last = b.last; b.last = NULL;
return;
}
// Store first pointer of Second Linked List
Node *second = b.first;
Node *third, **tmp = &third;
// We find first Node outside loop, smaller number, so Third pointer will store the first Node
// Then, we can only use tmp pointer for repeating process inside While loop
// Use while loop for repeating process until First or Second hit NULL
do
{
// If first Node data is smaller than second Node data
if (first->data < second->data)
{
*tmp = first;
tmp = &(first->next);
first = first->next;
}
// If first Node data is greater than second Node data
else
{
*tmp = second;
tmp = &(second->next);
second = second->next;
}
*tmp = NULL;
}
while (first && second);
// Handle remaining Node that hasn't pointed by Last after while loop
*tmp = (first) ? first : second;
// Change first to what Third pointing at, which is First Node
first = third;
// Change last pointer from old first linked list to new last Node, after Merge
Node *p = first;
while (p->next)
{
p = p->next;
}
last = p;
// Destroy second linked list because every Node it's now connect with first linked list
// This also prevent from Double free()
b.first = b.last = NULL;
}
int main()
{
int arr1[] = {4, 8, 12, 14, 15, 20, 26, 28, 30};
int arr2[] = {2, 6, 10, 16, 18, 22, 24};
int size1 = sizeof(arr1) / sizeof(arr1[0]);
int size2 = sizeof(arr2) / sizeof(arr2[0]);
LinkedList l1(arr1, size1);
LinkedList l2(arr2, size2);
LinkedList l3(l1);
LinkedList l4;
l1.Display();
l2.Display();
l3.Display();
l4.Display();
// Merge two linked list, pass l2 as reference
l3.Merge(l2);
l4 = l3;
l1.Display();
l2.Display();
l3.Display();
l4.Display();
return 0;
}
Demo
There are several questionable practices applied in this code, and there is also a bug.
First, the bug. When you create a list, it news all its nodes and keeps track of them using pointers. When you assign a list to another, you literally copy the pointer values. Not only have you now lost the nodes of the assigned list (because you overwrote them) and got a memory leak (because now there's no pointer pointing to the allocated nodes), you also now have the same pointers on two different lists, pointing to the same nodes. When the lists are destroyed, both of them try to delete their nodes, and you end up freeing the same memory twice. Yuk.
The solution to this bug is to implement the assignment operator.
Then, the questionable practices:
using namespace std; (Why is "using namespace std;" considered bad practice?)
You're assigning the members of LinkedList in the constructor body, instead of passing the values directly to their constructor in the initialization list. (What is this weird colon-member (" : ") syntax in the constructor?)
Declaring an array parameter (int[]) is declaring a pointer. Just be aware of it.
new cannot return NULL! It's useless to check its return value. If it can't allocate, it will simply throw an exception.
NULL is the inappropriate constant to use. You can use nullptr, it's the C++ equivalent of NULL, except it's type safe.
Manual memory management with new and delete is tricky to get right (as you figured out yourself). You might be interested in using std::unique_ptr or std::shared_ptr to alleviate the burden. They would have caught the bug.
Now, please: do not write in C++ like it's C with classes. I understand that you may not have encountered all of the features I presented here, but anyway now you know about them :)
The following is a basic code and I was wondering what was the basic way to write a loop on how to display the contents/data from the array of pointers. The top is a class with everything under public. Declaring a data of string followed by an array of pointers called next. In the main function, I'm declaring a few nodes and allocating memory to its followed by a string. A, B, and C. Towards the end of the code I'm connecting the pointers to each data and the last one C to NULL. And at the end, I'm having a bit of trouble writing or grasping the concept on how to write a loop to display it's contents, i.e Node1, Node2, Node3... Preferably a loop that'll display everything no matter the size.
#include <iostream>
using namespace std;
class node
{
public:
string data;
node * next;
};
int main()
{
node * A;
A = new node;
(*A).data = "node1";
node * B;
B = new node;
(*B).data = "node2";
node * C;
C = new node;
(*C).data = "node3";
(*A).next = B;
(*B).next = C;
(*C).next = NULL;
for(int i=0; *(next) != NULL; i++)
{
cout << *next[i[] << endl;
}
system("pause");
return 0;
}
use a temporary pointer that's initialized with the start of the node and use a while loop.
Node* tmp = A;
while (tmp) { // same as (tmp != NULL)
cout << tmp->data << endl;
tmp = tmp->next; // down the rabbit hole
}
Also, You could collapse the declaration of variables with assignment.
Node* A = new Node;
1.) remove for loop
printList(A);
void printList(node *first)
{
node *first = A;
while(first)
{
cout<<first->data<<endl;
}
}
I have a problem with copying some elements of list into the new one. It has to be done under one condition: elements that can be copied must be from entered range. The problem is that every single element is copied into newlist. Any suggestions? I want to note that my English is not perfect but I hope you gonna get it. Thank you :)
struct Node
{
Node* next;
int data;
};
struct List
{
Node* head;
Lista();
void push(int);
void addafter(int, int);
void delchosen(int);
void pop();
void print();
int count();
Node* find(int);
void pushback(int);
void popback();
void minmax(int&, int&);
List* range(int, int);
};
List::List()
{
head = NULL;
}
void List::push(int value)
{
Node *p = new Node;
p->data = value;
p->next = head;
head = p;
}
List* List::range(int x, int y)
{
Node* e = head;
List* newlist = new List;
while(e)
{
if(e->data > x && e->data <y)
{
newlist->push(e->data);
}
e = e->next;
}
return newlist;
}
int main()
{
List l;
srand(time(NULL));
const int size = 30;
int* arr = new int [size];
for(int i=0; i<size; i++)
{
arr[i]=rand()%20+1;
l.push(arr[i]);
}
l.range(3, 10);
return 0;
}
Didn't think it will be necessary, but I just have edited the code. Every single function works fine excepting this copying.
You never use the new list. That could probably mislead you. For example you could print or watch in the debugger the old list, which is still contain all the values. It happens sometimes with all the programmers, from freshmen to old long-bearded gurus.
Otherwise code should work:
auto newList = l.range(3, 10);
newList->print();
Bonus: General code review.
It would probably be easier to debug and test the code if you fill the list with deterministic values, rather than random content:
for (int i = 0; i < size; i++) {
l.push(i);
}
Most likely you don't need to allocate newlist on the heap. Use stack allocation:
List List::range(int x, int y) const {
...
List newlist;
...
newlist.push(...);
...
return newlist;
}
While it's nice and funny for self-education and various hacking, you should avoid using homebrew linked lists in the serious code. In C++ we tend to use Standard library facilities instead. Something like:
#include <iostream>
#include <iterator>
#include <list>
int main() {
// Construct original list from brace-initializer list
std::list<int> original{ 1, 2, 3, 4, 5, 6, 7 };
// Get the beginning of the new list by advancing
// beginning of the original list by 2 elements
auto begin = original.cbegin();
std::advance(begin, 2);
// Get the end of the new list by advancing
// beginning of the original list by 5 elements
auto end = original.cbegin();
std::advance(end, 5);
// Construct sublist from iterator range
std::list<int> sublist(begin, end);
// Print new list
for (auto&& e : sublist)
std::cout << e << ' '; // prints "3 4 5"
}
I have solved this problem!!! I found that if i have to use vector<Node*> children;. But I am not very sure the reason, can someone tell me why? Thanks:)
Question:
I use test.cpp to generate a tree structure like:
The result of (ROOT->children).size() is 2, since root has two children.
The result of ((ROOT->children)[0].children).size() should be 2, since the first child of root has two children. But the answer is 0, why? It really confuse for me.
test.cpp (This code is runnable in visual studio 2010)
#include <iostream>
#include <vector>
using namespace std;
struct Node {
int len;
vector<Node> children;
Node *prev;
Node(): len(0), children(0), prev(0) {};
};
class gSpan {
public:
Node *ROOT;
Node *PREV;
void read();
void insert(int);
};
int main() {
gSpan g;
g.read();
system("pause");
}
void gSpan::read() {
int value[4] = {1, 2, 2, 1};
ROOT = new Node();
PREV = ROOT;
for(int i=0; i<4; i++) {
insert(value[i]);
}
cout << "size1: " << (ROOT->children).size() << endl; // it should output 2
cout << "size2: " << ((ROOT->children)[0].children).size() << endl; // it should output 2
system("pause");
}
void gSpan::insert(int v) {
while(v <= PREV->len)
PREV = PREV->prev;
Node *cur = new Node();
cur->len = v;
cur->prev = PREV;
PREV->children.push_back(*cur);
PREV = cur;
}
The problem is that you children vector contains Node values rather than Node* pointers. While your access uses the root correctly, it finds only copies of the children you try to maintain. All of your nodes are also leaked.
You might want to use a std::vector<Node*> for your children and delete them at some point. The easiest way is probably to use a vector of smart pointers, e.g. a teference counted pointer, and have the smart pointer take care of the release.