I'm programming doubly linked list, everything was going fine but I faced with crash when reading a string value to the structure (code row is commented in the function "struct Node* GetNewNode()"):
#include <iostream>
#include <String>
#include <fstream>
#include <cstdlib>
using namespace std;
struct Node {
int sv;
double real;
bool log;
char simb;
string str;
struct Node* next;
struct Node* prev;
};
struct Node* head; // global variable - pointer to head node.
//----------------------------
struct Node* GetNewNode();
void Initialize(Node *stack);
void InsertAtTail(Node *stack);
void Print(Node *stack);
//----------------------------
//Creates a new Node and returns pointer to it.
ifstream fd("duom.txt");
struct Node* GetNewNode() {
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
fd >> newNode->sv;
fd >> newNode->real;
string loginis;
fd >> loginis;
if (loginis == "TRUE")
newNode->log = true;
else
newNode->log = false;
fd >> newNode->simb;
//fd >> newNode->str; //uncommented code in this row crashes the program
newNode->prev = NULL;
newNode->next = NULL;
return newNode;
}
//Inserts a Node at head of doubly linked list
void Initialize(Node *stack) {
stack = head;
}
//Inserts a Node at tail of Doubly linked list
void InsertAtTail(Node *stack) {
struct Node* temp = stack;
struct Node* newNode = GetNewNode();
if(head == NULL) {
head = newNode;
return;
}
while(temp->next != NULL)
temp = temp->next; // Go To last Node
temp->next = newNode;
newNode->prev = temp;
}
//Prints all elements in linked list in reverse traversal order.
void Print(Node *stack) {
struct Node* temp = stack;
if(temp == NULL)
return; // empty list, exit
// Going to last Node
while(temp->next != NULL)
temp = temp->next;
// Traversing backward using prev pointer
while(temp != NULL) {
cout << temp->sv << " ";
cout << temp->real << " ";
if (temp->log == true)
cout << "TRUE " << " ";
else
cout << "FALSE " << " ";
cout << temp->simb << " ";
//cout << temp->str << "\n";
temp = temp->prev;
}
printf("\n");
}
int main() {
/*Driver code to test the implementation*/
head = NULL; // empty list. set head as NULL.
// Calling an Insert and printing list both in forward as well as reverse direction.
Initialize(head);
InsertAtTail(head);
Print(head);
InsertAtTail(head);
Print(head);
fd.close();
}
Input data is:
4 5.27 TRUE $ asdf
6 7.3 TRUE # qwer
9 8.8 FALSE # zxvc
7 6.35 FALSE ! vbmn
1 0.89 TRUE % ghjk
Can somebody explain what is wrong here?
Instead of using C standard function malloc
struct Node* newNode = (struct Node*)malloc(sizeof(struct Node));
you have to use operator new
In this case the compiler will call a constructor of class std::string that to create data member str
Othewise object str of type std::string will not be created and the program will chash.
Function malloc simply allocates a raw memory of a requested size. It knows nothing about constructors of classes.
malloc allocates a raw block of memory. This is sufficient for simple (POD) datatypes which only store data. A std::string however needs to have its constructor called to be initialized correctly. Therefore you must allocate the node using new:
Node* newNode = new Node();
In general, malloc is very rarely needed in C++ (it doesn't call any constructors). It is a C-function.
Note that you need to call delete instead of free to free memory allocated by new.
Related
I want to accept a long string of numbers and insert in to a doubly linked list , with each node having 4 characters(numbers).
Below is my code. It takes the input as number, but says "Program finished with exist code 0"
Please help what did I am miss here?
#include <iostream>
#include <string>
#include <conio.h>
using namespace std;
struct Node {
string data;
struct Node* prev;
struct Node* next;
};
struct Node* head = NULL;
void insert(string newdata) {
struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));
newnode->data = newdata;
newnode->prev = NULL;
newnode->next = head;
if (head != NULL)
head->prev = newnode;
head = newnode;
cout << "\nNode inserted";
}
void display() {
struct Node* ptr;
ptr = head;
while (ptr != NULL) {
cout << ptr->data << " ";
ptr = ptr->next;
}
}
int main() {
string n1, temp;
cout << "Enter the number\n";
cin >> n1;
int len, i;
len = n1.size();
cout << "\n Length is " << len;
getch();
// temp= n1;
// cout<<"\n line is "<<temp.substr(len);
for (i = 0; i < len; i = i + 4) {
// temp = n1.substr(i,4);
insert(n1.substr(i, 4));
}
cout << "\nThe doubly linked list is: ";
display();
return 0;
}
As already pointed out in the comments section, the problem is that the constructor of the std::string object is not getting called, so that this object is not initialized properly.
The most straightforward fix to this would be to use placement new, which effectively does nothing else than to call the constructor. In order to do this, you can change the line
newnode->data = newdata;
to
new (&newnode->data) string( newdata );
This will call the copy (or move) constructor on the std::string object.
However, a more C++ style solution to the problem would be not to use malloc at all, but to instead use new, and to write a proper constructor for struct Node, which invokes the copy or move constructor of the string object. In order to do this, you could define struct Node like this:
struct Node {
//copy and move constructor
Node( const string &data, Node* prev = nullptr, Node* next = nullptr )
: data(data), prev(prev), next(next) {}
Node( const string &&data, Node* prev = nullptr, Node* next = nullptr )
: data(data), prev(prev), next(next) {}
string data;
struct Node* prev;
struct Node* next;
};
Now you can replace the lines
struct Node* newnode = (struct Node*)malloc(sizeof(struct Node));
newnode->data = newdata;
newnode->prev = NULL;
newnode->next = head;
with this single line:
Node* newnode = new Node( newdata, nullptr, head );
Hi I have the following code, and keep getting memory leaks, can someone help me fix this please, I've been at this for hours but cant seem to find why there is a memory leak, I am new with nodes, I think the problem is with the destructor, but can't seem to pin point exactly what, please help!
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node* next;
};
class LinkedList {
public:
LinkedList() { // constructor
head = NULL;
}
~LinkedList(); // destructor
void insert(int val);
void display();
private:
Node* head;
};
LinkedList::~LinkedList() { delete head; }
// function to add node to a list
void LinkedList::insert(int val) {
Node* newnode = new Node();
newnode->data = val;
newnode->next = NULL;
if (head == NULL) {
head = newnode;
} else {
Node* temp = head; // head is not NULL
while (temp->next != NULL) {
temp = temp->next; // go to end of list
}
temp->next = newnode; // linking to newnode
}
}
void LinkedList::display() {
if (head == NULL) {
cout << "List is empty!" << endl;
} else {
Node* temp = head;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
}
int main() {
LinkedList* list = new LinkedList();
list->insert(999);
list->insert(200);
list->insert(300);
list->insert(700);
list->insert(500);
cout << "Linked List data" << endl;
list->display();
delete list;
return 0;
}
An alternative to Abel's answer with the Node-destroying Nodes:
LinkedList::~LinkedList()
{
while (head)
{
Node * temp = head;
head = head->next;
delete temp;
}
}
The LinkedList loops removes, and deletes the first Node until there are no Nodes left.
Why do I prefer this approach? Two reasons:
Ownership. Who is responsible for managing the nodes? With the loop, managing the Nodes is entirely in the hands of LinkedList. If Nodes can destroy one another, management is split between LinkedList and Node, and both owners need to remain in agreement about the state of the managed resource. Maintaining this agreement is tricky and tricky means more code you can get wrong. For example, if LinkedList isn't careful when removing a single Node from the list, that Node will recursively destroy the rest of the list. Ooops.
The second reason is recursion. If the list gets too long, the program will exhaust its automatic storage (Usually causing a Stack Overflow) and become unstable. You've limited the size of the list you can handle unnecessarily and the only way you'll know you've exceeded the limit is when the program fails.
The access violation the Asker has been experiencing I have been unable to reproduce. I may have accidentally fixed it.
I don't think you want destructing a node to delete the entire list. You could but I think each node should be independent of the others - the linked list class is where list level things should happen.
Also, you don't want the destructor to contain the code to clear the list because you may want to clear the list at some arbitrary point - so the linked list should have a clear function that is called from the linked list destructor and can be called from other places too.
So the destructor would call this function to clear the list:
void LinkedList::clear() {
Node* next;
Node* temp = head;
while (temp != NULL) {
next = temp->next;
delete temp;
temp = next;
}
head = NULL;
}
The whole code would be:
#include <iostream>
using namespace std;
class Node {
public:
int data;
Node* next;
Node() : data(0), next(NULL) {
cout << "Constructed default node\n";
}
Node(int data) : data(data), next(NULL) {
cout << "Constructed node: " << data << "\n";
}
~Node() {
cout << "Destructed node: " << data << "\n";
}
};
class LinkedList{
public:
LinkedList() { // constructor
head = NULL;
}
~LinkedList() {
clear();
}
void insert(int val);
void display();
void clear();
private:
Node* head;
};
// function to add node to a list
void LinkedList::insert(int val) {
Node* newnode = new Node(val);
if (head == NULL) {
head = newnode;
}
else {
Node* temp = head; // head is not NULL
while (temp->next != NULL) {
temp = temp->next; // go to end of list
}
temp->next = newnode; // linking to newnode
}
}
// function to delete the entire list
void LinkedList::clear() {
Node* next;
Node* temp = head;
while (temp != NULL) {
next = temp->next;
delete temp;
temp = next;
}
head = NULL;
}
// function to display the entire list
void LinkedList::display() {
if (head == NULL) {
cout << "List is empty!" << endl;
}
else {
Node* temp = head;
while (temp != NULL) {
cout << temp->data << " ";
temp = temp->next;
}
cout << endl;
}
}
int main() {
LinkedList list;
cout << "Creating List\n";
list.insert(999);
list.insert(200);
list.insert(300);
list.insert(700);
list.insert(500);
cout << "Linked List data:\n";
list.display();
cout << "Clearing list\n";
list.clear();
cout << "Creating List\n";
list.insert(400);
list.insert(600);
cout << "Linked List data:\n";
list.display();
cout << "NOT clearing list (should happen automatically\n";
return 0;
}
You can try it here: https://onlinegdb.com/HJlOT1ngqP
The output:
Creating List
Constructed node: 999
Constructed node: 200
Constructed node: 300
Constructed node: 700
Constructed node: 500
Linked List data:
999 200 300 700 500
Clearing list
Destructed node: 999
Destructed node: 200
Destructed node: 300
Destructed node: 700
Destructed node: 500
Creating List
Constructed node: 400
Constructed node: 600
Linked List data:
400 600
NOT clearing list (should happen automatically
Destructed node: 400
Destructed node: 600
I'm trying to transition from an almost entirely Java background to getting comfortable with C++. I'm practicing by trying to build a basic Linked List.
#include <iostream>
#include <string>
using namespace std;
struct node
{
string data;
node *next = NULL;
};
class linkedlist
{
public:
node *head;
public:
linkedlist()
{
head = NULL;
}
void addNode(string s)
{
node *newNode = new node;
newNode->data = s;
if(head == NULL)
head = newNode;
else
{
node *temp = head->next;
while(temp != NULL)
temp = temp->next;
temp = newNode;
}
}
void printList()
{
node *temp = head;
while(temp != NULL)
{
cout << temp->data << '\n';
temp = temp->next;
}
}
};
The issue at hand is that once I add a new node using void addNode(string s), it does not appear when I attempt to print the list (starting from the head) with void printList().
For example:
int main(int argc, const char * argv[])
{
int n;
string str;
linkedlist list;
cout << "Please enter the number of strings you'd like to enter:\n";
cin >> n;
for(int i = 0;i < n;i++)
{
string temp;
cout << "Enter string #" << i + 1 << '\n';
cin >> temp;
list.addNode(temp);
}
cout << "This is your linked list: ";
list.printList();
return 0;
}
Using main() above, my results become:
This is your linked list:
(string 1)
I'm pretty certain I'm using pointers improperly here but I don't see why. I've done as much digging as I can on my own for some clarification on how I could be doing this wrong but I'm coming up blank.
Thanks for any clarification you folks can provide.
The problem is here:
node *temp = head->next;
while(temp != NULL)
temp = temp->next;
temp = newNode;
You're traversing the list, then setting temp to the value of the newNode. When temp goes out of scope, the value for newNode isn't stored anyplace.
What you want to do is set the next pointer of the last node to the value of newNode, i.e.
node *temp = head;
while(temp->next != NULL)
temp = temp->next;
temp->next = newNode;
The code above traverses the list until it finds a node that doesn't have a next node, and sets its next node to the newNode, thus adding it to the list.
Could anyone tell me if this is the basic idea of linked lists? What are the pros and cons to this method and what are best practices when implementing linked lists in C++? Im new to data structures so this is my first approach. If there is a better way to do this same thing, please let me know. Additionally, how would you create the nodes dynamically without hard coding it? Thanks.
#include <iostream>
#include <string>
using namespace std;
struct node {
int x;
node *next;
};
int main()
{
node *head;
node *traverser;
node *n = new node; // Create first node
node *t = new node; // create second node
head =n; //set head node as the first node in out list.
traverser = head; //we will first begin at the head node.
n->x = 12; //set date of first node.
n->next = t; // Create a link to the next node
t->x = 35; //define date of second node.
t->next = 0; //set pointer to null if this is the last node in the list.
if ( traverser != 0 ) { //Makes sure there is a place to start
while ( traverser->next != 0 ) {
cout<< traverser->x; //print out first data member
traverser = traverser->next; //move to next node
cout<< traverser->x; //print out second data member
}
}
traverser->next = new node; // Creates a node at the end of the list
traverser = traverser->next; // Points to that node
traverser->next = 0; // Prevents it from going any further
traverser->x = 42;
}
for tutorial purpose, you can work out this example:
#include <iostream>
using namespace std;
struct myList
{
int info;
myList* next;
};
int main()
{
//Creation part
myList *start, *ptr;
char ch = 'y';
int number;
start = new myList;
ptr = start;
while (ptr != NULL)
{
cout << "Enter no. ";
cin >> ptr->info;
cout << "Continue (y/n)? ";
cin >> ch;
if (ch == 'y')
{
ptr->next = new myList;
ptr = ptr->next;
}
else
{
ptr->next = NULL;
ptr = NULL;
}
}
//Traversal part begins
cout << "Let's start the list traversal!\n\n";
ptr = start;
while (ptr!=NULL)
{
cout << ptr->info << '\n';
ptr = ptr->next;
}
}
It allocates memory dynamically for as many elements as you want to add.
I'd prefer to make a linked list class. This eliminates the need to call 'new' more than once. A nice implementation with examples can be found here.
You are in fact already doing dynamic allocation. So, not sure what you are asking for. But if you want to define functions to add new nodes to your linked list (or delete a node etc.), this can be a probable solution:
The location nodes get inserted/deleted is dependent on the type of data-structure. In a queue, new nodes will get added to the end; at the top in case of a stack. A function that adds a node to the top, simulating STACK push operation:
void pushNode(node **head, int Value) {
node *newNode = new node;
newNode->x = Value;
newNode->next = *head;
*head = newNode;
}
It would be called like pushNode(&head, 15) where 'head' would be defined as node *head = NULL. The root head should initially be set to NULL. After this operation head will point to the newly added node (top of stack).
The approach would be very similar for other data-structures (viz. queues) and works fine. But as you are using C++, I would suggest to define a class for your linked-list and define these functions as methods. That way, it will be more convenient and less error-prone.
Even better use std::list. It's the standard thing, so much portable and robust than a custom implementation.
You can also do it in this way
#include <iostream>
using namespace std;
struct Node{
int data;
Node* next;
};
void createList(Node** head ,Node* temp){
int n;
char ch;
temp = *head;
while(temp != NULL){
cout<<"Enter The Value ";
cin>>temp->data;
cout<<"DO you want to continue(y/n)";
cin>>ch;
if(ch=='Y' || ch == 'y'){
temp->next = new Node;
temp = temp->next;
}else{
temp->next = NULL;
temp = NULL;
}
}
}
void ShowList(Node* head){
cout<<"your list :"<<endl;
while(head != NULL){
cout<<head->data<<" ";
head = head->next;
}
}
int main()
{
//Creation part
Node *head, *temp;
createList(&head,temp);
ShowList(head);
}
I wanted to test the following code (which works fine for a non-null list) to see what would happen in the case of an empty list (in which case the head would be null).
hence the code which applies to filling the list is commented out..
But for some strange reason, the test for NULL in print_nodes() just doesnt seem to work. ive added some debug cout calls to see (and also checked using gdb) but whilst the value does indeed appear to be NULL, any if statements dont seem to test the equivalence properly..
any idea why?
many thanks!
#include <iostream>
using namespace std;
struct node {
char dat;
node *nextPtr;
};
//inserts new node and returns pointer
node* new_node(char data, node* prevNode);
//adds a new node at the head ofthe list
void new_head (node *head_, char dat_);
//inserts new node after *before
void insert_node (node *before, char dat_);
//runs through and prints the list - requires first node (head)
void print_nodes (node *head);
int main() {
cout <<endl << endl;
cout << endl << "*******************RUN******************" <<endl <<endl;
node* head = NULL;
if (head == NULL) {
cout << "head null"; //this works here
}
//head non-standard
// node* head = new node;
// head->dat ='a';
/*
node* b = new_node('b', head);
node* c = new_node('c', b);
node* d = new_node('d', c);
node* e = new_node('e', d);
node* f = new_node('f', e);
*/
print_nodes(head);
insert_node(head,'N');
print_nodes(head);
cout << endl << "*******************END RUN******************" <<endl;
return 0;
}
node* new_node(char data, node* prevNode) {
node* tempPtr = new node;
tempPtr->dat = data;
tempPtr->nextPtr = NULL; //standard
prevNode->nextPtr = tempPtr;
return tempPtr;
}
void new_head (node *head_, char dat_) {
}
void insert_node (node *before, char dat_) {
node* tempPtr = new node;
tempPtr->dat = dat_;
tempPtr->nextPtr = before->nextPtr;
before->nextPtr = tempPtr;
}
void print_nodes (node *head) {
node* tempPtr = head;
cout << "\nPrinting nodes..." <<endl;
if (tempPtr == NULL) { //this test is not working.. why?
cout << "tempPtr is NULL";
return;
} else { //only run in the non null case
for (tempPtr; tempPtr != NULL; tempPtr = tempPtr->nextPtr) {
cout << "Current node content: " << tempPtr->dat <<endl;
}
}
}
You have a problem: head was not allocated, but insert accesses its "next element":
before->nextPtr = tempPtr;
head is passed in as before, and you didn't allocate memory for head. Hence you dereference a NULL pointer here.
Could it be that your application crashes as a result, and the printout to cout isn't done because cout is buffered?
Try to:
Remove the call to insert
Change cout to cerr (unbuffered)
Report the results of these changes.
allocate head before insertion :
node * head = new node;
memset(head, 0, sizeof(node));
The code works for me using g++ 4.4.1 on windows. The message is displayed and then it crashes, because of other issues in the code. You are probably not seeing the message because the crash occurs before the output buffer containing the message is flushed.
In general, it is a good idea to write diagnostic messages to standard error (cerr) rather than standard output, as the error stream is not buffered.