I am using a doubly linked list and I am trying to use the data that is passed by reference to insert a node before said data. I've used string* data = new string(s); to allocate memory however, when I try to use data I get an error.
#ifndef __DOUBLYLINKEDLIST_H__
#define __DOUBLYLINKEDLIST_H__
//
//
#include
#include
using namespace std;
class DoublyLinkedList {
public:
DoublyLinkedList();
~DoublyLinkedList();
void append (const string& s);
void insertBefore (const string& s);
void insertAfter (const string& s);
void remove (const string& s);
bool empty();
void begin();
void end();
bool next();
bool prev();
bool find(const string& s);
const std::string& getData() const;
private:
class Node
{
public:
Node();
Node(const string& data);
~Node();
Node* next;
Node* prev;
string* data;
};
Node* head;
Node* tail;
Node* current;
};
void DoublyLinkedList::insertBefore(const string& s)
{
Node* ptr = head;
string* data = new string(s);
if (head == NULL)
{
append(s);
return;
}
if (head == current)
{
//this is where I get an error...
this->data= new Node();
current->prev = head;
current = head;
return;
}
There is no reason to use a pointer to a string, which forces you to manage memory. Use a simple string instead.
But this is not the problem here. Here a local variable has the same name than a class member of a Node , and the member in node gets never initalized. Furtherthermore the DoublyLinkedList has itself no such member, so this->data is unknown. See my comments here:
void DoublyLinkedList::insertBefore(const string& s)
{
...
string* data = new string(s); // --> ok, but this is local variable
if (head == NULL)
{
append(s);
return; // ouch !!! memory leak !! data pointer is never freed
}
if (head == current)
{
//this is where I get an error...
this->data= new Node(); // --> 'this' is a DoublyLinkedList, not a Node
...
return;
}
Now this being said, is it possbile that you make a confusion between the DoublyLinkedList and the nodes it contains ? See here a start of correction, but you need to do more to handle the linking between the nodes:
void DoublyLinkedList::insertBefore(const string& s)
{
Node* ptr = head;
if (head == NULL)
{
append(s);
return;
}
if (head == current)
{
string* data = new string(s);
Node nd = new Node();
nd->data = data; // initialize node's pointer
nd->prev = ... // you need to link new node to the rest
nd->next = ...
... // and you need to update the previous and next node
return;
}
Now, as said in the first place, replace the pointer to string with a string. At least, you'll avoid leaking memory, shallow copies, and lots of other troubles. Then you can focus better on the real problems of a linked list data structure.
Related
i need to code a linked list for university in c++, mostly to practice coding iterators.
I tested it with some basic cases and it works but after i pass it in valgrind and the test server for the program i get a list of different errors. Maybe somebody can help me not to despair.
(At the end i will append the error list)
template <typename T = float>
class ForwardList
{
struct Node
{
/// Constructs a Node from a data value and a link to the next element.
Node(const T &data, Node *next) : data{data}, next{next} {}
/// A Node owns all nodes after it, so it deletes them on destruction
~Node() { delete next; }
//Performs a deep copy of the Node and all Nodes after it. Bad practice but we got it like that
Node *clone() const
{
if (next == nullptr)
{
return new Node{data, nullptr};
}
else
{
return new Node{data, next->clone()};
}
}
T data;
Node *next;
};
public:
ForwardList() : head(nullptr) {}
/// Copy constructor performs a deep copy of the other list's Nodes
ForwardList(const ForwardList &other)
{
head = other.head->clone();
}
/// Destructor makes sure that all Nodes are correctly destroyed
~ForwardList()
{
while (head->next != nullptr)
{
Node *tmp = head;
head = head->next;
delete tmp;
}
delete head;
}
/// Copy assignment operator uses the copy-and-swap idiom to make a safe
/// assignment
ForwardList &operator=(ForwardList other)
{
swap(*this, other);
return *this;
}
/// Add an element to the front of the list.
void push_front(const T &value)
{
std::cout << "Num: " << numberOfNodes << std::endl;
Node *item = new Node(value, nullptr);
if (head==nullptr)
{
head = item;
}else
{
item->next=head;
head = item;
}
numberOfNodes++;
}
/// Remove the first element of the list. Calling this function on an empty
/// list is undefined behavior. When implementing this function, be careful
/// to delete the one and only the one element that is removed.
void pop_front()
{
Node *item;
item = head->next;
delete head;
head = item;
numberOfNodes--;
}
/// Get a reference to the first element of the list
/// (const and non-const version)
T &front()
{
return head->data;
}
const T &front() const
{
return head->data;
}
/// Return true is the list is empty
bool empty() const
{
return numberOfNodes == 0 ? true : false;
}
std::size_t size() const
{
return numberOfNodes;
}
friend void swap(ForwardList &l, ForwardList &r)
{
Node *tmp = l.head;
l.head = r.head;
r.head = tmp;
}
private:
Node *head;
size_t numberOfNodes = 0;
};
And now the fun part (i will put it on pastebin because its pretty long):
https://pastebin.com/4JAKkJtP
Your issue is that ~Node tries to delete its next, and you also try to walk the list in ~ForwardList. By deleting ~Node(), you let ForwardList handle cleanup and everything works.
The clue here is that valgrind reported use after free, meaning something was deleting a pointer twice. That was a clue to look at everything that deletes a Node* (or really, delete in general).
I am trying to create an insertAfter function where it accepts a value by reference and then inserts that value after the current node. I am unsure how to implement the code.
Below is the header file and what I have tried but it does not compile.
#include <iostream>
#include <string>
class DoublyLinkedList {
public:
DoublyLinkedList();
~DoublyLinkedList();
void append (const string& s);
void insertBefore (const string& s);
void insertAfter (const string& s);
void remove (const string& s);
bool empty();
void begin();
void end();
bool next();
bool prev();
bool find(const string& s);
const std::string& getData() const;
private:
class Node
{
public:
Node();
Node(const string& data);
~Node();
Node* next;
Node* prev;
string* data;
};
Node* head;
Node* tail;
Node* current;
};
void DoublyLinkedList::insertAfter(const string& s)
{
// Node *temp, *var;
//var=(Node *)malloc(sizeof(Node));
if(head == NULL)
{
append(s);
}
temp->data=current;
}
void DoublyLinkedList::append(const string& s)
{
//create a new Node
current = new Node(s);
if (this->empty())//check if it is empty or not
{
this->head = this->tail = current;
}else{
//append to tail
current->prev = tail;
tail->next = current;
tail = current;
}
}
#endif
-Create a new node and store the data passed in. Set the current pointer to head.
Node * newNode = new Node(s);
current=head;
-You must traverse over the LinkedList using a loop which checks the values of each node using 2 pointers, one which trails behind the one that checks the node values.
while(current->data != insertAfter-
>data)
{
current=current->next;}
-Once the proper node is found with current, the loop should stop. Set the new node's next pointer to the insertAfter's next pointer, and the prev pointer to the insertAfter node.
newNode->next = insertAfterNode->next;
newNode->prev = insertAfterNode;
-You then set current's next pointer to the node you'd like to insert.
current->next = newNode;
Also, be sure to add each potential case. If it is the tail that was inserted after, be sure to set the tail pointer to newNode and same if it is inserted at the head. After traversing with the loop, put:
if(tail->data==current->data)
{
tail = newNode;
}
if(head->data==current->data)
{
head=newNode;
}
Edit: because this is a doubly LinkedList, the prev pointer can be implemented in place of trailCurrent, which is not needed at all.
How can I create a linked node so that each linked node contains 2 items in a single node? Im not sure if I'm going in the right direction. I have 2 private members in my class, and I'm not sure if I need 2 set functions or if I can have a single set function with 2 parameters. For example void setItem(const string& anItem, const string secondItem);
#ifndef _NODE
#define _NODE
#include<string>
using namespace std;
class Node
{
private:
string item; // A data item
Node* next; // Pointer to next node
public:
Node();
Node(const string& anItem);
Node(const string& anItem, Node* nextNodePtr);
void setItem(const string& anItem);
void setNext(Node* nextNodePtr);
string getItem() const ;
Node* getNext() const ;
}; // end Node
#include "Node.cpp"
#endif
This is my Node.cpp file:
#include "Node.h"
#include <cstddef>
#include<string>
using namespace std;
Node::Node() : next(nullptr)
{
} // end default constructor
Node::Node(const string& anItem) : item(anItem), next(nullptr)
{
} // end constructor
Node::Node(const string& anItem, Node* nextNodePtr) :
item(anItem), next(nextNodePtr)
{
} // end constructor
void Node::setItem(const string& anItem)
{
item = anItem;
} // end setItem
void Node::setNext(Node* nextNodePtr)
{
next = nextNodePtr;
} // end setNext
string Node::getItem() const
{
return item;
} // end getItem
Node* Node::getNext() const
{
return next;
} // end getNext
For me, I'd go for two public functions for setting the two items of the node. One function will modify only one item, while the other function will modify the two item. Like:
// Function that will only set one item
void Node::setIndexItem(const int propNum, const string val)
{
if (propNum == 1) { // You may use 0 for the first item
this.item = val;
} else if (propNum == 2) { // You may use 1 for the second item
this.item2 = val;
} else {
// You may want to raise an exception here. Depends on you really.
}
}
// Function that will set the two items
void Node::setItems(const string val1, const string val2)
{
this.item = val1;
this.item2 = val2;
}
In your case, I would create a dedicated class for the data
struct DataNode
{
std::string key;
std::string value;
};
That separates class responsabilities (List may be focussed to link node).
That would allow you to modify data type without changing your class List (a templated list would be even better, but out of scope).
And then, your Node class would be something like:
class Node
{
private:
DataNode data;
Node* next; // Pointer to next node // I assume you can't use unique_ptr :-/
public:
Node();
Node(const DataNode& data);
Node(const DataNode& data, Node* nextNodePtr);
// Rule of 3
Node(const Node& rhs);
~Node();
Node& operator =(const Node& rhs);
// data accessor
void setItem(const DataNode& data);
const DataNode& getItem() const;
DataNode& getItem();
// Internal utility
void setNext(Node* nextNodePtr);
const Node* getNext() const;
Node* getNext();
};
I added a non-const version of the getter to allow modifying part of the item:
node.getItem().value = "new value";
I'm relatively new to C++ and I have an issue which I really do not understand. My code creates a linked list. It is actually longer than this, but I chopped it down for the purpose of this question.
When I run the code, it adds three nodes and then when it goes to delete the node with the URI b, it calls the delete operator and ends up deleting the node, but then it seems to go back to delete operator (when I step through it) and it kills my whole list.
#include <iostream>
#include <string>
#include <cstdlib>
#include <cstdio>
using namespace std;
class CLinkedList
{
protected:
class ip_uri_store
{
public:
string uri, ip;
ip_uri_store* next;
ip_uri_store(const string& URI, const string& IP) {uri = URI, ip = IP, next = NULL;}
};
typedef ip_uri_store* nodeAddress;
nodeAddress head;
void AddNode(const string&, const string&, nodeAddress);
void DeleteNode(const string&, nodeAddress, nodeAddress);
public:
CLinkedList() {head = NULL;}
void AddNode(const string& URI, const string& IP) {AddNode(URI, IP, head);}
void DeleteNode(const string& URI) {DeleteNode(URI, head, head);}
};
void CLinkedList::AddNode(const string& URI, const string& IP, nodeAddress node)
{
nodeAddress temp = new ip_uri_store(URI, IP);
temp->uri = URI;
temp->ip = IP;
temp->next = head;
head = temp;
}
void CLinkedList::DeleteNode(const string& URI, nodeAddress node, nodeAddress behindNode)
{
if(node)
{
if(!node->uri.compare(URI))
node == head ? head = head->next : behindNode->next = node->next;
else
DeleteNode(URI, node->next, node);
delete node;
}
}
int main(int argc, char* argv[])
{
CLinkedList lList;
lList.AddNode("a", "1");
lList.AddNode("b", "2");
lList.AddNode("c", "3");
lList.DeleteNode("b");
return 0;
}
You are calling delete node; even if the comparison fails (i.e. node->uri != URI).
if(!node->uri.compare(URI))
{
node == head ? head = head->next : behindNode->next = node->next;
delete node;
}
else
DeleteNode(URI, node->next, node);
Also, the condition seems to be inverted.
First, you should use std::list and avoid reinventing the world.
Anyway, if you are stuck to this implementation for some reason :
temp->uri = URI; and temp->ip = IP; in the AddNode method are useless because the members are already initialized in the constructor of ip_uri_store class.
the deletion of the head of the list occurs because the 'delete node' should only be done in the case node->uri.compare(URI) in the DeleteNode method.
Again, you should seriously consider using standard classes...
You are calling delete on all the nodes. It needs to be moved inside the conditional so you only delete the nodes that match the URI
if(!node->uri.compare(URI)) {
node == head ? head = head->next : behindNode->next = node->next;
delete node;
} else {
DeleteNode(URI, node->next, node);
}
I'm not very good at this, and I am a bit stuck making the copy constructor for a single linked list and the nodes that go with it.
Here is my header file:
#pragma once
#include <iostream>
using namespace std;
class Node
{
public:
int data;
Node* next;
Node()
{
next = NULL;
data = 0;
}
Node(const Node& copyNode); /*: data(copyNode.data), next(copyNode.next ? new Node(*copyNode.next) : NULL)*/
};
class SLLIntStorage
{
public:
Node* head;
Node* current;
Node* tail;
void Read(istream&);
void Write(ostream&);
void setReadSort(bool);
void sortOwn();
void print();
void mergeSort(Node**);
Node *merge(Node*, Node*);
void split(Node*, Node**, Node**);
bool _sortRead;
int numberOfInts;
SLLIntStorage(const SLLIntStorage& copying) //: head(copying.head ? new Node(*copying.head) : NULL)
{
}
SLLIntStorage(void);
~SLLIntStorage(void);
};
inline ostream& operator<< (ostream& out, SLLIntStorage& n)
{
n.Write(out);
return out;
}
inline istream& operator>> (istream& in, SLLIntStorage& s)
{
s.Read(in);
return in;
}
Could anyone give me a hand on understanding how this works and what I could do to create it? Thank you.
To copy a linked list, you must iterate the entire linked list and make a copy of each of the nodes, and append that to the new list. Remember that you don't just copy the pointers, but you must copy the entire Node structure and any data that needs copying as well (e.g. if the datas are pointers, you'll need to do deep copying on those too).
So here's an example copy constructor for your SLLIntStorage class:
SLLIntStorage(const SLLIntStorage& copying) : head(NULL)
{
Node* cur = copying.head;
Node* end = NULL;
while (cur)
{
Node* n = new Node;
n->data = cur->data;
if (!head) {
head = n;
end = head;
} else {
end->next = n;
end = n;
}
cur = cur->next;
}
}
Note that I didn't take into account the tail and current data members, etc. You'll have to account for those.
As it is homework, I will try to give the idea from which you can figure out what you need to do with the copy constructors.
Node(const Node& copyNode) : data(copyNode.data),
next(copyNode.next)
{
// ....
}
In the above snippet you are just actually making the next to point the location copyNode::next is pointing to. So, you run in to problems when any of the pointer deallocates the resource it is pointing to leaving the other dangling.
So, you should make the pointer next each instance to point to a location it independently holds. So, -
Node(const Node& copyNode) : data(copyNode.data),
next(new Node)
{
(*next) = *(copyNode.next) ;
// ....
}
Also read this thread which has an excellent explanation - Rule of Three