Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 7 years ago.
Improve this question
I'm trying to test out the code my professor gave us. We have to change the implementation of the code but that is not what I am stuck on. I am stuck on making a working test code. He gave me the test code to run but when I try to run it I keep getting errors which shouldn't be the case. Could anyone tell me what the problem is in my test code so I can start changing and adding different functions into my code? Thanks
Here is my code:
// ListNode.h
#ifndef _LISTNODE_H
#define _LISTNODE_H
#include <cstdlib>
typedef int ItemType;
class ListNode {
friend class LList;
public:
ListNode(ItemType item, ListNode* link = NULL);
private:
ItemType item_;
ListNode *link_;
};
inline ListNode::ListNode(ItemType item, ListNode *link)
{
item_ = item;
link_ = link;
}
#endif // _LISTNODE_H
// LList.h
#ifndef _LLIST_H
#define _LLIST_H
#include "ListNode.h"
class LList {
public:
LList();
LList(const LList& source);
~LList();
LList& operator=(const LList& source);
int size() { return size_; }
void append(ItemType x);
void insert(size_t i, ItemType x);
ItemType pop(int i = -1);
ItemType& operator[](size_t position);
private:
// methods
void copy(const LList &source);
void dealloc();
ListNode* _find(size_t position);
ItemType _delete(size_t position);
// data elements
ListNode *head_;
int size_;
};
#endif // _LLIST_H
// LList.cpp
#include "LList.h"
LList::LList()
{
head_ = NULL;
size_ = 0;
}
ListNode* LList::_find(size_t position)
{
ListNode *node = head_;
size_t i;
for (i = 0; i<position; i++) {
node = node->link_;
}
return node;
}
ItemType LList::_delete(size_t position)
{
ListNode *node, *dnode;
ItemType item;
if (position == 0) {
dnode = head_;
head_ = head_->link_;
item = dnode->item_;
delete dnode;
}
else {
node = _find(position - 1);
if (node != NULL) {
dnode = node->link_;
node->link_ = dnode->link_;
item = dnode->item_;
delete dnode;
}
}
size_ -= 1;
return item;
}
void LList::append(ItemType x)
{
ListNode *node, *newNode = new ListNode(x);
if (head_ != NULL) {
node = _find(size_ - 1);
node->link_ = newNode;
}
else {
head_ = newNode;
}
size_ += 1;
}
void LList::insert(size_t i, ItemType x)
{
ListNode *node;
if (i == 0) {
head_ = new ListNode(x, head_);
}
else {
node = _find(i - 1);
node->link_ = new ListNode(x, node->link_);
}
size_ += 1;
}
ItemType LList::pop(int i)
{
if (i == -1) {
i = size_ - 1;
}
return _delete(i);
}
ItemType& LList::operator[](size_t position)
{
ListNode *node;
node = _find(position);
return node->item_;
}
LList::LList(const LList& source)
{
copy(source);
}
void LList::copy(const LList &source)
{
ListNode *snode, *node;
snode = source.head_;
if (snode) {
node = head_ = new ListNode(snode->item_);
snode = snode->link_;
while (snode) {
node->link_ = new ListNode(snode->item_);
node = node->link_;
snode = snode->link_;
}
size_ = source.size_;
}
LList& LList::operator=(const LList& source)
{
if (this != &source) {
dealloc();
copy(source);
}
return *this;
}
LList::~LList()
{
dealloc();
}
void LList::dealloc()
{
ListNode *node, *dnode;
node = head_;
while (node) {
dnode = node;
node = node->link_;
delete dnode;
}
}
#include "LList.h"
#include <iostream>
using namespace std;
int main()
{
LList b, c;
int x;
b.append(1);
b.append(2);
b.append(3);
c.append(4);
c.append(5);
c = b;
x = b.pop();
cout << c;
}
Could anyone help me write a working test code, this the last thing I will need to start adding my different functions.
I keep getting this error:
Error 1 error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'LList' (or there is no acceptable conversion) c:\users\koopt_000\documents\visual studio 2013\projects\lab10\lab10\testlist.cpp 18 1 Lab10
Any help?
In your code:
cout << c;
is the problem. You cannot print your linked list that way (Edit: Unless you have an overload for the operator << which does not appear in your code).
For printing the elements, you can iterate through the list starting from the first node to the last. Something like that would work:
void LList::printList()
{
ListNode *tmp = head_;
while(tmp) {
std::cout<<tmp->item_;
tmp=tmp->link_;
}
}
PS: don`t forget the put the method prototype into the class definition. And of course in your main method can call to the function as follows:
...
c.printList();
....
Hope that helps!
You are attempting to output your LList, but it's not quite that straight forward. You need to overload the output operator:
friend std::ostream& operator<< (std::ostream& stream, const LList& list) {
// Write code here to iterate through the list
// and output each item...
// Return the stream so we can chain outputs..
return stream;
}
Related
Im trying to implement a few data structures in c++, just to understand them better.
I have a question about the implementation. In general, if I have self-defined objects as fields of another objects, is it better to define a pointer to heap allocated memory of the object, or just a field of the object?
Consider the following example:
I tried to implement a basic stack as linked list, so one of the field (actually the only one) of the stack is a linked list, but Im not sure if this field should be a pointer to linked list (which is allocated in heap memory and initiallized in the constructor) or just a linked list.
Here's the implementation;
#ifndef STACKASLINKEDLIST_H
#define STACKASLINKEDLIST_H
#include "LinkedList.h"
template <class T>
class StackAsLinkedList
{
public:
//|-------------------- Constructors --------------------
StackAsLinkedList(){}
//|-------------------- Methods --------------------
void push(const T& toAdd){
data.add(toAdd,0);
}
T& pop() {
return data.remove(0);
}
T& peek() const{
T tmp = pop();
push(tmp);
return tmp;
}
bool isEmpty() const {
return data.isEmpty();
}
//|-------------------- Friend functions --------------------
friend std::ostream& operator<<(std::ostream& out, const StackAsLinkedList<T>& mStack){
out<<mStack.data;
return out;
}
//|-------------------- Destructors --------------------
virtual ~StackAsLinkedList(){}
protected:
private:
LinkedList<T> data;
};
#endif // STACKASLINKEDLIST_H
As I wrote it, I used as a filed just the LinkedList it self, Im not sure if its worst or better and if the implementation of the destructor works fine. Basically, in my implementation of LinkedList, anytime I push something to the stack a new Link appended to the LinkedList and this Link is allocated in the heap memory, so I do want the destructor of the stack to erase this memory.
I'd really appreciate a guidance/tips here. What is the best way to deal with the questions I asked? (Also I'd really appreciate any suugestions about improvements of the implemtation).
In case it is important to the question, here is my implementation of LinkedList
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include "List.h"
#include "Link.h"
template <class T>
class LinkedList : public List<T>
{
public:
//|-------------------- Constructors --------------------
LinkedList(): List<T>(),head(NULL) {} //|Default constructor.
LinkedList(const LinkedList<T>& other): List<T>() { //|Copy constructor.
head = other.head;
Link<T>* otherCurr = other.head->next;
Link<T>* thisCurr = head;
while(otherCurr){
thisCurr->next = new Link<T>(otherCurr->m_data);
thisCurr = thisCurr->next;
otherCurr = otherCurr->next;
this->m_size++;
}
}
//|-------------------- Methods --------------------
bool isEmpty() const {
return head==NULL;
}
int getSize() const {
return this->m_size;
}
void add(T data,int index ){ //|Complexity time is O(n) because complexity time of getLink() is O(n).
//|If we had a pointer to the position, this function complexity would be O(1).
if(index > this->m_size){
std::cout<<"Out Of Bounds"<<std::endl;
return;
}
else if (index == this->m_size)
addLast(data);
else if (index == 0)
addFirst(data);
else{
Link<T>* toAdd = new Link<T>(data);
Link<T>* prevLink = getLink(index-1);
Link<T>* indexLink = prevLink->next;
prevLink->next = toAdd;
toAdd->next = indexLink;
}
this->m_size++;
}
void set(int index, T data){
if(index >= this->m_size){
std::cout<<"Out Of Bounds"<<std::endl;
return;
}
Link<T>* indexLink = getLink(index);
indexLink->m_data = data;
}
T remove(int index){
if(head== NULL){
std::cout<<"The list is empty"<<std::endl;
return NULL;
}
if(index > this->m_size-1){
std::cout<<"Out Of Bounds"<<std::endl;
return NULL;
}
if (index ==0 ){
Link<T>* tmp = head;
head = head->next;
T toReturn = tmp->m_data;
delete tmp;
return toReturn;
}
Link<T>* prevLink = getLink(index-1);
Link<T>* tmp = prevLink->next;
prevLink->next = tmp->next;
T toReturn = tmp->m_data;
delete tmp;
this->m_size--;
return toReturn;
}
//|-------------------- Operator overload --------------------
T operator[](int index) const { //|Complexity time is O(n).
Link<T>* relevantLink = getLink(index);
if(relevantLink)
return relevantLink->m_data;
else
return NULL;
}
bool operator==(const List<T>& other) const{ //|Complexity time is O(n).
if(! (typeid(other) == typeid(*this)))
return false;
if(this->m_size != other.getSize())
return false;
Link<T>* thisCurr = head;
int i=0;
while(thisCurr != NULL ){
if(thisCurr->m_data != other[i])
return false;
i++;
thisCurr = thisCurr->next;
}
return true;
}
//|-------------------- Friend functions --------------------
friend std::ostream& operator<<(std::ostream& out, const LinkedList<T>& mList){
Link<T>* curr = mList.head;
while(curr->next){
out<< (*curr)<<" -> ";
curr = curr->next;
}
out<<(*curr);
return out;
}
//|-------------------- Destructors --------------------
virtual ~LinkedList(){
Link<T> *curr, *prev;
curr= head;
while(curr){
prev = curr;
curr = curr->next;
delete prev;
}
}
private:
//|-------------------- Private fields --------------------
Link<T>* head;
//|-------------------- Private Methods --------------------
Link<T>* getLink(int index) const{ //|Complexity time is O(n).
if(index >= this->m_size -1){
std::cout<<"Out of bounds"<<std::endl;
return NULL;
}
int counter =0;
Link<T>* curr = head;
while(counter < index){
counter++;
curr = curr->next;
}
return curr;
}
void addFirst(T data){
Link<T>* toAdd = new Link<T>(data);
if (head == NULL){
head = toAdd;
return;
}
toAdd->next = head;
head = toAdd;
}
void addLast(T data){
Link<T>* toAdd = new Link<T>(data);
if (head == NULL){
head = toAdd;
return;
}
Link<T>* curr = head;
while (curr->next != NULL)
curr = curr->next;
curr->next = toAdd;
}
};
#endif // LINKEDLIST_H
I am trying to make a way to take two Linked List objects (doubly-linked), say LL1 and LL2, and remove the 'overlapping' elements within LL1 which also appear in LL2.
So for example if:
LL1 = {1,2,3};
LL2 = {9,2,8};
I want an output of:
LL1 = {1,3};
I am trying to do this via overloading the '-=' operator to work with two linked list objects. It compiles fine, but I'm getting a 'segmentation fault (core dumped)' error during runtime at the '-=' operator call. Not sure why. Below is my code. Any help would be appreciated, thankyou kindly.
Node.h:
// Node.h
/*******************************/
// Last Updated: Tues Aug 31 2021
// Program Description: Header file for Node
#ifndef NODE_H
#define NODE_H
#include <iostream>
#include <cstdlib>
#include "EToll.h"
using namespace std;
class Node {
public:
typedef EToll value_type; //typedef - now value_type is synonym for EToll object
//Constructors:
Node(); //default
Node(value_type&); //constructor with 1 arg - data item
Node(const value_type& i, Node* n, Node* p); //specific constructor with 3 arguments
//Destructor:
~Node();
//mutators (setters):
void set_next(Node*);
void set_prev(Node*);
void set_data(const value_type&);
//accessors (getters):
Node* get_next() const;
Node* get_prev() const;
value_type& get_data();
private:
Node* next; //ptr to next (or NULL)
Node* prev; //ptr to prev (or NULL)
value_type data; //the payload
};
#endif
Node.cpp:
// Node.cpp
/*******************************/
// Last Updated: Tues Aug 31 2021
// Program Description: Implementation of Node
#include "Node.h"
#include <cstdlib>
//Constructors:
Node::Node() //default constructor
{
data = value_type(); //creates an empty EToll object, since value_type is a synonym for EToll
next = NULL;
prev = NULL;
}
Node::Node(value_type& item) //constructor with 1 argument - a data item
{
data = item;
next = NULL;
prev = NULL;
}
Node::Node(const value_type& i, Node* n, Node* p) //constructor with 3 arguments
{
data = i;
next = n;
prev = p;
}
//Empty destructor:
Node::~Node(){}
//Mutators (setters):
void Node::set_next(Node* next_ptr) {next = next_ptr;}
void Node::set_prev(Node* prev_ptr) {prev = prev_ptr;}
void Node::set_data(const value_type& new_data) {data = new_data;}
//Accessors (getters):
Node* Node::get_next() const {return next;}
Node* Node::get_prev() const {return prev;}
/* Note that get_data() has Node::value_type& instead of value_type& as it's return type as the
compiler doesn't check if the return type of a function is part of a member function, and thus
it doesn't look in Node for a value_type. A more detailed explanation can be found at: https://stackoverflow.com/questions/68991650/error-value-type-does-not-name-a-type-in-c */
Node::value_type& Node::get_data() {return data;}
LinkedList.h:
// LinkedList.h
/*******************************/
// Last Updated: Tues Aug 31 2021
// Program Description: Header file for LinkedList
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include "Node.h"
#include <iostream>
#include <cstdlib>
#include <string>
class LinkedList
{
public:
typedef Node::value_type value_type;
//Constructor:
LinkedList();
//Destructor:
~LinkedList();
//Insert function:
//void insert(value_type& item);
//length function:
int length();
//count function:
int count(string);
//totalIncome function:
double totalIncome();
//addTo functions:
void addToHead(value_type&);
void addToTail(value_type&);
//accessors (getters):
value_type& getHead();
Node* getHeadAdd();
value_type& getTail();
//remove functions:
void removeFromHead();
void removeFromTail();
void remove(string);
void removeByNode(Node* c); //remove a particular node
//search funciton:
//Preconditions: None
//Postconditions: Current points to the first Node storing the target, and true is returned. If not present, current is NULL and false is returned
bool search(const value_type& target);
//concatenation operator (+=) overload:
//Preconditions: LL1 and LL2 are instances of LinkedList
//Postconditions: Each Node of LL2 is traversed. At each individual Node, itis appended to LL1
LinkedList operator += (const LinkedList& LL2);
//remove overlap operator (-=) overload:
//Preconditions: LL1 and LL2 are instances of LinkedList
//Postconditions: Each Node of LL2 is traversed. At each individual Node, it's match is searched for within LL1. If a match is found, the matching Node in LL1 is deleted and the next node in LL2 is traversed
LinkedList operator -= (const LinkedList& LL2);
//NEED A .COUNT FUNCTION!!
private:
Node* head;
Node* tail;
Node* current;
};
//stream insertion operator (<<) overload:
//Preconditions: LinkedList obj "LL" exists and we wish to output it
//Postconditions: LL exists without change
ostream& operator << (ostream& out, LinkedList& LL);
#endif
LinkedList.cpp:
// LinkedList.cpp
/*******************************/
// Last Updated: Wed Aug 31 2021
// Program Description: Implementation of LinkedList
#include "LinkedList.h"
#include <cstdlib>
//Constructors:
LinkedList::LinkedList() //default constructor
{
head = NULL;
tail = NULL;
current = NULL;
}
//Empty destructor:
LinkedList::~LinkedList(){}
//length() function:
//Preconditions: None
//Postconditions: A count of the nodes is returned (ie no of nodes in the LinkedList)
int LinkedList::length()
{
int answer = 0;
for (current = head; current != NULL; current = current->get_next())
{
answer++;
}
return answer;
}
//count function:
int LinkedList::count(string type)
{
int returnCount = 0;
//cycle through LinkedList:
for (current = head; current != NULL; current = current->get_next())
{
//check for match:
if (type == current->get_data().get_type())
{
//increment the counter
returnCount++;
}
}
return returnCount;
}
//totalIncome function:
double LinkedList::totalIncome()
{
double returnTotal = 0;
//cycle through LinkedList:
for (current = head; current != NULL; current = current->get_next())
{
returnTotal = returnTotal + current->get_data().get_charge();
}
return returnTotal;
}
//addToHead function:
//Preconditions: None
//Postconditions: A new node storing the supplied item is created and linked in to be list's new head
void LinkedList::addToHead(Node::value_type& item)
{
Node* newNode = new Node(item);
//Check if the list is empty:
if (length() == 0)
{ //list is empty, so:
head = newNode;
tail = newNode;
} else
{ //list is not empty, so:
head->set_prev(newNode);
newNode->set_next(head);
head = newNode;
}
/*
head = new Node(item, head, NULL);
//In case the list is empty:
if (tail == NULL)
{
tail = head;
}
*/
}
//addToTail function:
//Preconditions: None
//Postconditions: A new node storing the supplied item is created and linked in to be list's new tail
void LinkedList::addToTail(Node::value_type& item)
{
Node* newNode = new Node(item);
//Check if the list is empty:
if (length() == 0)
{ //list is empty, so:
head = newNode;
tail = newNode;
} else
{ //list is not empty, so:
tail->set_next(newNode);
newNode->set_prev(tail);
tail = newNode;
}
}
//getHead function:
Node::value_type& LinkedList::getHead()
{
return head->get_data();
}
//getHeadAdd function:
Node* LinkedList::getHeadAdd()
{
return head->get_next()->get_prev();
}
//getTail function:
Node::value_type& LinkedList::getTail()
{
return tail->get_data();
}
//removeFromHead function:
void LinkedList::removeFromHead()
{
Node* temp;
temp = head->get_next();
if (head != NULL)
{
temp->set_prev(NULL);
head = temp;
} else
{ //list is empty, so update the tail
tail = NULL;
}
}
//removeFromTail function:
void LinkedList::removeFromTail()
{
Node* temp;
temp = tail->get_prev();
if (head != NULL)
{
temp->set_next(NULL);
tail = temp;
} else
{ //list is empty, so update the head
head = NULL;
}
}
//remove function: removes a Node by a string input
void LinkedList::remove(string l)
{
//cycle through LinkedList:
for (current = head; current != NULL; current = current->get_next())
{
//check for match:
if (l == current->get_data().get_licence() && current == head)
{
removeFromHead();
} else if (l == current->get_data().get_licence() && current == tail)
{
removeFromTail();
} else if (l == current->get_data().get_licence())
{
//delete the node
removeByNode(current);
} else
{
//do nothing, move on to next iteration of for loop
}
}
}
//removeByNode function:
//Preconditions: input c points to a node to be removed
//Postconditions: the node pointed to by c before is now gone. current now points to head
void LinkedList::removeByNode(Node* c)
{
current = c;
current->get_prev()->set_next(current->get_next());
current->get_next()->set_prev(current->get_prev());
delete current;
current = head;
}
//search function:
bool LinkedList::search(const Node::value_type& target)
{
for (current = head; current != NULL; current = current->get_next())
{
if (target == current->get_data())
{
return true;
}
}
//else:
return false;
}
// += operator overload (new):
LinkedList LinkedList::operator += (const LinkedList& LL2)
{
LinkedList* t = this;
Node* temp = LL2.head;
while (temp != NULL)
{
t->addToTail(temp->get_data());
temp = temp->get_next();
}
return *t;
}
// -= operator overload:
LinkedList LinkedList::operator -= (const LinkedList& LL2)
{
LinkedList* t = this;
Node* temp1;
Node* temp2;
//Cycle through LL2:
for (temp2 = LL2.head; temp2 != NULL; temp2 = temp2->get_next())
{
//Cycle through LL1:
for (temp1 = t->head; temp1 != NULL; temp1 = temp1->get_next())
{
//Check if current of LL1 has a match in LL2:
if (temp1->get_data() == temp2->get_data())
{
t->removeByNode(temp1);
}
}
}
return *t;
}
-= operator overload (within LinkedList.cpp, just putting it here under new heading for easy location):
// -= operator overload:
LinkedList LinkedList::operator -= (const LinkedList& LL2)
{
LinkedList* t = this;
Node* temp1;
Node* temp2;
//Cycle through LL2:
for (temp2 = LL2.head; temp2 != NULL; temp2 = temp2->get_next())
{
//Cycle through LL1:
for (temp1 = t->head; temp1 != NULL; temp1 = temp1->get_next())
{
//Check if current of LL1 has a match in LL2:
if (temp1->get_data() == temp2->get_data())
{
t->removeByNode(temp1);
}
}
}
return *t;
}
-= operator call within another 'main()' program:
LinkedList tollBooth1;
LinkedList tollBooth2;
LinkedList dailyReport;
//(add data to tollBooth 1 and 2, merge these 2 objects into dailyReport)
//removing the contents of both booths from daily report:
dailyReport -= tollBooth1;
dailyReport -= tollBooth2;
You've included way too much code. The general ask on this site is to provide a minimal reproducible example.
Problems
I have no idea why you have a member variable named current. It often points to deleted memory.
You need to implement the "rule of three" or the "rule of five" on your LinkedList class. If you copy the LinkedList, and then modify it, you will have dangling pointers.
LinkedList a;
LinkedList b = a;
a.RemoveHead();
// b.head is now pointing to deleted memory.
LinkedList::removeByNode(Node* c) does not update the head and tail member variables if the removed node was the head or tail respectively.
Your operator-= uses temp1 after it has been deleted.
There are likely more issues.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I am currently working on a program that uses a Hash table. I have worked on my own Hash table class and the program works but then crashes after it has already done the work involving the hash table. The error I get is a Access Violation reading location error. I have spent hours going through my code and still cannot find what I'm doing wrong or why the program is crashing. Here are my problem classes below:
Hashtable.h:
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include <string>
#include "LinkedList.h"
#include <iostream>
using namespace std;
class hashTable
{
public:
hashTable();
virtual ~hashTable();
void insertNode(string nodeData);
bool removeNode(string nodeKey);
Node * checkForDuplicate( string nodeData );
private:
LinkedList * tableArray;
int length;
int hash(string stateKey);
};
#endif // HASHTABLE_H
Hashtable.cpp:
#include "hashTable.h"
hashTable::hashTable()
{
length = 181667;
tableArray = new LinkedList[length];
}
int hashTable::hash(string stateKey) {
int multiplier = 1;
int total = 0;
int l = stateKey.length();
for(int i = l - 1; i > -1; --i) {
int temp;
temp = (stateKey[i] - '0') * multiplier;
total += temp;
multiplier = multiplier * 10;
}
return(total) % length;
}
void hashTable::insertNode(string stateData) {
Node * newNode;
newNode = new Node;
newNode->data = stateData;
int index = hash(newNode -> data);
tableArray[index].insertNode(newNode);
delete newNode;
}
bool hashTable::removeNode(string nodeKey) {
int index = hash(nodeKey);
return tableArray[index].removeNode(nodeKey);
}
Node * hashTable::checkForDuplicate( string nodeData )
{
int index = hash( nodeData );
return tableArray[ index ].getNode(nodeData);
}
hashTable::~hashTable()
{
delete [] tableArray;
//dtor
}
LinkedList.h:
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include<string>
#include<iostream>
using namespace std;
struct Node {
string data;
Node *next;
};
class LinkedList
{
public:
LinkedList();
void insertNode(Node * newNode);
bool removeNode(string stateData);
Node * getNode(string stateData);
int getLength();
virtual ~LinkedList();
private:
Node * top;
int length;
};
#endif // LINKEDLIST_H
LinkedList.cpp:
#include "LinkedList.h"
LinkedList::LinkedList()
{
top = new Node;
top->next = NULL;
length = 0;
}
void LinkedList :: insertNode(Node * newNode) {
Node * a = top;
Node * b = top;
while(b) {
a = b;
b = a -> next;
if (a== NULL) { break; }
}
a -> next = newNode;
newNode -> next = NULL;
length++;
}
bool LinkedList :: removeNode(string stateData) {
if(!top -> next){
return false;
}
Node * a = top;
Node * b = top;
while(b) {
if(b->data == stateData) {
a->next = b->next;
delete b;
length--;
return true;
}
a = b;
b = a ->next;
}
return false;
}
Node * LinkedList :: getNode(string stateData) {
if(top == NULL) { return NULL ;}
Node * current = top;
while (current->next != NULL) {
if((current->data == stateData)) {
return current;
}
current = current -> next;
}
return NULL;
}
int LinkedList :: getLength() {
return length;
}
LinkedList::~LinkedList()
{
Node * a = top;
Node * b = top;
while (b) {
a = b;
b = a->next;
if(b) delete a;
}
}
Your hashTable::insertNode() method is allocating a new Node object, then passing it to LinkedList::insertNode() to take ownership of the object, but then delete's it afterwards, thus leaving the LinkedList with a dangling pointer to invalid memory. Any access to that node will cause undefined behavior. DO NOT delete the new node after LinkedList takes ownership of it.
It would be better if LinkedList::insertNode() took a string as input instead of a Node* pointer. Let LinkedList allocate the new node internally.
Also, there are some other minor issues with your LinkedList() implementation in general (like not following the Rule of Three, and not using a double-linked list for more efficient inserts and removals).
Try something more like this instead:
Hashtable.h:
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include <string>
#include "LinkedList.h"
class hashTable
{
public:
hashTable();
hashTable(const hashTable &src);
~hashTable();
void insertNode(const std::string &nodeData);
bool removeNode(const std::string &nodeData);
bool checkForDuplicate(const std::string &nodeData);
hashTable& operator=(const hashTable &rhs);
private:
std::vector<LinkedList> tableArray;
int length;
int hash(const std::string &nodeData);
};
#endif // HASHTABLE_H
Hashtable.cpp:
#include "hashTable.h"
hashTable::hashTable()
: length(181667), tableArray(new LinkedList[length])
{
}
hashTable::hashTable(const hashTable &src)
: length(src.length), tableArray(new LinkedList[length])
{
for (int i = 0; i < length; ++i)
tableArray[i] = src.tableArray[i];
}
hashTable::~hashTable()
{
delete[] tableArray;
}
hashTable& hashTable::operator=(const hashTable &rhs)
{
hashTable tmp(rhs);
std::swap(tableArray, tmp.tableArray);
std::swap(length, tmp.length);
return *this;
}
int hashTable::hash(const std::string &nodeData)
{
int multiplier = 1;
int total = 0;
int l = nodeData.length();
for(int i = l - 1; i > -1; --i)
{
int temp = (nodeData[i] - '0') * multiplier;
total += temp;
multiplier *= 10;
}
return total % length;
}
void hashTable::insertNode(const std::string &nodeData)
{
int index = hash(nodeData);
tableArray[index].insertNode(nodeData);
}
bool hashTable::removeNode(const std::string &nodeData)
{
int index = hash(nodeData);
return tableArray[index].removeNode(nodeData);
}
bool hashTable::checkForDuplicate(const std::string &nodeData)
{
int index = hash(nodeData);
return (tableArray[index].getNode(nodeData) != NULL);
}
LinkedList.h:
#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include <string>
struct Node
{
std::string data;
Node *previous;
Node *next;
};
class LinkedList
{
public:
LinkedList();
LinkedList(const LinkedList &src);
~LinkedList();
void insertNode(const std::string &nodeData);
bool removeNode(const std::string &nodeData);
Node* getNode(const std::string &nodeData);
int getLength();
LinkedList& operator=(const LinkedList &rhs);
private:
Node *head;
Node *tail;
int length;
};
#endif // LINKEDLIST_H
LinkedList.cpp:
#include "LinkedList.h"
#inclue <algorithm>
LinkedList::LinkedList()
: head(NULL), tail(NULL), length(0)
{
}
LinkedList::LinkedList(const LinkedList &src)
: head(NULL), tail(NULL), length(0)
{
Node *current = src.top;
while (current != NULL)
{
insertNode(current->data);
current = current->next;
}
}
LinkedList::~LinkedList()
{
Node *current = top;
while (current != NULL)
{
Node *next = current->next;
delete current;
current = next;
}
}
LinkedList& LinkedList::operator=(const LinkedList &rhs)
{
LinkedList tmp;
Node *current = rhs.top;
while (current != NULL)
{
tmp.insertNode(current->data);
current = current->next;
}
std::swap(top, tmp.top);
std::swap(bottom, tmp.bottom);
std::swap(length, tmp.length);
return *this;
}
void LinkedList::insertNode(const string &nodeData)
{
Node *newNode = new Node;
newNode->data = nodeData;
newNode->previous = NULL;
newNode->next = NULL;
if (top == NULL) top = newNode;
if (bottom != NULL)
{
newNode->previous = bottom;
bottom->next = newNode;
}
bottom = newNode;
length++;
}
bool LinkedList::removeNode(const string &nodeData)
{
Node* node = getNode(nodeData);
if (node != NULL)
{
if (node->next != NULL)
node->next->previous = node->previous;
if (node->previous != NULL)
node->previous->next = node->next;
if (top == node)
top = node->next;
if (bottom == node)
bottom = node->previous;
delete node;
length--;
return true;
}
return false;
}
Node* LinkedList::getNode(const string &nodeData)
{
Node *current = top;
while (current != NULL)
{
if (current->data == nodeData)
return current;
current = current->next;
}
return NULL;
}
int LinkedList::getLength()
{
return length;
}
With that said, you can then get rid of LinkedList altogether by using std::list instead, and simplify hashTable's memory management by using std::vector:
Hashtable.h:
#ifndef HASHTABLE_H
#define HASHTABLE_H
#include <string>
#include <list>
#include <vector>
class hashTable
{
public:
hashTable();
void insertNode(const std::string &nodeData);
bool removeNode(const std::string &nodeData);
bool checkForDuplicate(const std::string &nodeData);
private:
std::vector< std::list<std::string> > tableArray;
int hash(const std::string &stateKey);
};
#endif // HASHTABLE_H
Hashtable.cpp:
#include "hashTable.h"
#include <algorithm>
hashTable::hashTable()
: tableArray(181667)
{
}
int hashTable::hash(const std::string &nodeData)
{
int multiplier = 1;
int total = 0;
int l = nodeData.length();
for(int i = l - 1; i > -1; --i)
{
int temp = (nodeData[i] - '0') * multiplier;
total += temp;
multiplier *= 10;
}
return total % length;
}
void hashTable::insertNode(const std::string &nodeData)
{
int index = hash(nodeData);
tableArray[index].push_back(nodeData);
}
bool hashTable::removeNode(const string &nodeData)
{
int index = hash(nodeData);
std::list<std::string>::iterator iter = std::find(tableArray[index].begin(), tableArray[index].end(), nodeData);
if (iter != tableArray[index].end())
{
tableArray[index].erase(iter);
return true;
}
return false;
}
bool hashTable::checkForDuplicate(const std::string &nodeData)
{
int index = hash(nodeData);
std::list<std::string>::iterator iter = std::find(tableArray[index].begin(), tableArray[index].end(), nodeData);
return (iter != tableArray[index].end());
}
I am really new to C++ and this code was an example in my book so it should work because I have to implement a few new functions into this. However, I copied the code line for line and I keep getting this error message now my code won't compile until I fix it.
It says that my local pointer 'node' is being used. I don't know what this actually means. Could anyone tell me whats is the error actually telling me? Also could some one help me fix this so I can start my project? I'm only asking for the code because this isn't part of my project, it was already given by the teacher.
Here is my code:
// ListNode.h
#ifndef _LISTNODE_H
#define _LISTNODE_H
#include <cstdlib>
typedef int ItemType;
class ListNode {
friend class LList;
public:
ListNode(ItemType item, ListNode* link = NULL);
private:
ItemType item_;
ListNode *link_;
};
inline ListNode::ListNode(ItemType item, ListNode *link)
{
item_ = item;
link_ = link;
}
#endif // _LISTNODE_H
// LList.h
#ifndef _LLIST_H
#define _LLIST_H
#include "ListNode.h"
class LList {
public:
LList();
LList(const LList& source);
~LList();
LList& operator=(const LList& source);
int size() { return size_; }
void append(ItemType x);
void insert(size_t i, ItemType x);
ItemType pop(int i = -1);
ItemType& operator[](size_t position);
private:
// methods
void copy(const LList &source);
void dealloc();
ListNode* _find(size_t position);
ItemType _delete(size_t position);
// data elements
ListNode *head_;
int size_;
};
#endif // _LLIST_H
// LList.cpp
#include "LList.h"
LList::LList()
{
head_ = NULL;
size_ = 0;
}
ListNode* LList::_find(size_t position)
{
ListNode *node = head_;
size_t i;
for (i = 0; i<position; i++) {
node = node->link_;
}
return node;
}
ItemType LList::_delete(size_t position)
{
ListNode *node, *dnode;
ItemType item;
if (position == 0) {
dnode = head_;
head_ = head_->link_;
item = dnode->item_;
delete dnode;
}
else {
node = _find(position - 1);
if (node != NULL) {
dnode = node->link_;
node->link_ = dnode->link_;
item = dnode->item_;
delete dnode;
}
}
size_ -= 1;
return item;
}
void LList::append(ItemType x)
{
ListNode *node, *newNode = new ListNode(x);
if (head_ != NULL) {
node = _find(size_ - 1);
node->link_ = newNode;
}
else {
head_ = newNode;
}
size_ += 1;
}
void LList::insert(size_t i, ItemType x)
{
ListNode *node;
if (i == 0) {
head_ = new ListNode(x, head_);
}
else {
node = _find(i - 1);
node->link_ = new ListNode(x, node->link_);
}
size_ += 1;
}
ItemType LList::pop(int i)
{
if (i == -1) {
i = size_ - 1;
}
return _delete(i);
}
ItemType& LList::operator[](size_t position)
{
ListNode *node;
node = _find(position);
return node->item_;
}
LList::LList(const LList& source)
{
copy(source);
}
void LList::copy(const LList &source)
{
ListNode *snode, *node;
snode = source.head_;
if (snode) {
node = head_ = new ListNode(snode->item_);
snode = snode->link_;
}
while (snode) {
node->link_ = new ListNode(snode->item_);
node = node->link_;
snode = snode->link_;
}
size_ = source.size_;
}
LList& LList::operator=(const LList& source)
{
if (this != &source) {
dealloc();
copy(source);
}
return *this;
}
LList::~LList()
{
dealloc();
}
void LList::dealloc()
{
ListNode *node, *dnode;
node = head_;
while (node) {
dnode = node;
node = node->link_;
delete dnode;
}
}
I know where the problem is exactly (Line 104 in my code)
node->link_ = new ListNode(snode->item_);
This part of my code is the problem. Could anyone help me fix this problem so I can work on my program? Thanks!
Now that my previous problem was answered I have a new one.
How would I go about testing my code? I have a few lines but it keeps coming out with errors when I try to print out the contents of my LList. This is my test code:
#include "LList.h"
int main()
{
LList b, c;
int x;
b.append(1);
b.append(2);
b.append(3);
c.append(4);
c.append(5);
c = b;
x = b.pop();
}
Could anyone help me write a working test code, this the last thing I will need to start adding my different functions.
This is probably due to warnings being treated as errors in your build. The compiler is complaining that node might not be initialized when node->link is accessed. However, that won't actually be the case because if snode is null, the while block won't be accessed, so you won't access the uninitialized memory. If you want to make the warning go away, putting the while loop inside the if block will probably work:
snode = source.head_;
if (snode) {
node = head_ = new ListNode(snode->item_);
snode = snode->link_;
while (snode) {
node->link_ = new ListNode(snode->item_);
node = node->link_;
snode = snode->link_;
}
}
This is a false warning as the compiler seems to think you are going to use the node without having assigned it (because it might skip the if statement). In this scenario I do not see how this would happen as the while (snode) would never be entered.
You could simply ignore this warning (disable treat warnings as errors in the project settings) or remove this warning from this specific part of code (#pragma warning(disable : 4703)).
To build without treating warnings as errors go to: Project -> Properties -> C/C++ -> Treat warnings as errors. Disable this option or use the pragma directives.
For academic purposes, I'm trying to develop a little "textual adventure game". I have to implement all data structures by my own. Now, I have some problems with the implementation of a generic (template) LinkedList.
In the specific, this data structure works with everything (primitive data types and custom objects) BUT strings! (standard library strings).
When I try to add strings to a list, the application crashes with the following error (in console):
"terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_constructor null not valid"
The list is implemented as a "double linked list" using the head-node as first-last node
Here the code ("Abstract" List interface):
#ifndef LIST_H_
#define LIST_H_
template <class T>
class List
{
public:
virtual ~List() {}
virtual T get(int position) = 0;
virtual List* add(T item) = 0;
virtual List* insert(T item, int position) = 0;
virtual List* remove(int position) = 0;
virtual int size() const = 0;
virtual bool isEmpty() const = 0;
protected:
private:
};
#endif /* LIST_H_ */
This is the LinkedList implementation (the "node" class):
#include "List.h"
#include <stdlib.h>
#ifndef LINKEDLIST_H_
#define LINKEDLIST_H_
template <class T>
class ListNode
{
public:
ListNode(T item)
{
mItem = item;
mNext = NULL;
mPrev = NULL;
}
ListNode(T item, ListNode<T>* next, ListNode<T>* prev)
{
mItem = item;
mNext = next;
mPrev = prev;
}
~ListNode()
{
delete &mItem;
}
T getItem()
{
return mItem;
}
ListNode<T>* getNext()
{
return mNext;
}
ListNode<T>* getPrev()
{
return mPrev;
}
void setItem(T item)
{
mItem = item;
}
void setNext(ListNode<T>* next)
{
mNext = next;
}
void setPrev(ListNode<T>* prev)
{
mPrev = prev;
}
protected:
private:
T mItem;
ListNode<T> *mNext, *mPrev;
};
The LinkedList class:
template <class K>
class LinkedList : public List<K>
{
public:
LinkedList()
{
mSize = 0;
mFirstNode = NULL;
}
~LinkedList()
{
// implementazione distruttore tramite ciclo sui nodi
}
K get(int position)
{
K item = NULL;
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL) item = targetNode->getItem();
return item;
}
List<K>* add(K item)
{
if (mFirstNode == NULL)
{
mFirstNode = new ListNode<K>(item);
mFirstNode->setNext(mFirstNode);
mFirstNode->setPrev(mFirstNode);
}
else
{
ListNode<K>* newNode = new ListNode<K>(item, mFirstNode, mFirstNode->getPrev());
mFirstNode->getPrev()->setNext(newNode);
mFirstNode->setPrev(newNode);
}
mSize++;
return this;
}
List<K>* insert(K item, int position)
{
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL)
{
ListNode<K>* newNode = new ListNode<K>(targetNode->getItem(), targetNode->getNext(), targetNode);
targetNode->setItem(item);
targetNode->setNext(newNode);
mSize++;
}
return this;
}
List<K>* remove(int position)
{
ListNode<K>* targetNode = getNodeAtPosition(position);
if (targetNode != NULL)
{
targetNode->setItem(targetNode->getNext()->getItem());
targetNode->setNext(targetNode->getNext()->getNext());
//delete targetNode->getNext();
mSize--;
}
return this;
}
int size() const
{
return mSize;
}
bool isEmpty() const
{
return (mFirstNode == NULL) ? true : false;
}
protected:
ListNode<K>* getNodeAtPosition(int position)
{
ListNode<K>* current = NULL;
if (mFirstNode != NULL && position < mSize)
{
current = mFirstNode;
for (int i = 0; i < position; i++)
{
current = current->getNext();
}
}
return current;
}
private:
int mSize;
ListNode<K>* mFirstNode;
};
#endif /* LINKEDLIST_H_ */
Suggestions?
Part of your problem is here:
ListNode(T item)
{
mItem = item; // for a std::string, this will be a class member, non-pointer
mNext = NULL;
mPrev = NULL;
}
ListNode(T item, ListNode<T>* next, ListNode<T>* prev)
{
mItem = item; // same here
mNext = next;
mPrev = prev;
}
~ListNode()
{
delete &mItem; // you are attempting to delete an item you never created
}
You should either change your constructors to create a T* object on the heap (which will then be deleted in your destructor), or remove the delete line from your destructor.
This problem will be evident with far more than just std::string, by the way.
Somewhere in your program you are doing this:
std::string s(nullptr);
Calling std::string's constructor with a null pointer is causing it to throw a std::logic_error exception.
From the standard:
ยง 21.4.2
basic_string(const charT* s, size_type n, const Allocator& a = Allocator());
Requires: s shall not be a null pointer and n < npos.
It seems it's not possible to pass std::string as template argument...
Strings as Template Arguments
Now I use an "old" - char const* - to achieve the expected result, even if I have to implement my personal "utils" methods to work with those pointers now...