String class using linked list - c++

I have to write this String class which is represented using linked list. I seem to have problems with my copy constructor and I have no idea how to write my assignment operator. Any idea where the mistake is and how to write them? The shown code is for the copy constructor with the following operation String s="word". I'm not sure how to write one for String s1=s2. Here is my code so far:
struct Element
{
char data;
Element* next;
};
class String
{
Element* top;
public:
String();
bool empty() const;
char last() const;
char pop();
void push(char);
friend std::ostream& operator<<(std::ostream&, const String&);
friend std::istream& operator>>(std::istream&, String&);
String(const char*);
};
String::String(const char *p)
{
int l = strlen(p);
for(int i=0; i < l+1 ; i++)
{
Element *newElement;
newElement = new Element;
newElement->data = p[i];
newElement->next = NULL;
if(top == NULL)
{
top = newElement;
}
else
{
Element *tmp = top;
while(tmp->next != NULL)
{
tmp = tmp->next;
tmp->next = newElement;
}
}
}
}
int main()
{
String s="Hello";
std::cout<<s;//operator<< works tested it
}

If you defined single-linked list when it is much better to add new elements at the head of the list instead of the tail. Nevertheless your function could look the following way
String::String(const char*p)
{
for ( ; *p; ++p )
{
Element *newElement = new Element;
newElement->data = *p;
newElement->next = NULL;
if ( top == NULL )
{
top = newElement;
}
else
{
Element *tmp = top;
while ( tmp->next != NULL ) temp = tmp->next;
tmp->next = newElement;
}
}
}
By the way it is not a copy constructor. As for the copy constructor then it could be defined as
String::String( const String &s ) : top( NULL )
{
if ( s.top )
{
top = new Element;
top->data = s.top->data;
top->next = NULL;
for ( Element *tmp1 = top, tmp2 = s.top; tmp2->next; tmp1 = tmp1->next, tmp2 = tmp2->next )
{
tmp1->next = new Element;
tmp1->next->data = tmp2->next->data;
tmp1->next->next = NULL;
}
}
}

In the following code, your while loop will never execute since the top->next will be NULL.
Element *tmp = top;
while(tmp->next != NULL)
{
...
}
Also, as #Claptrap commented, you assign newElement on every loop iteration.
Given all of this, I'm not seeing why it would fail, but it may be in code that you have not posted. Please try to reduce your code to the minimum necessary that reproduces the problem and then include that code in your post.

Related

I can't assign the struct node's variables in linked list class. when I assign them to anything it creates undefined behaviour

//method for printing list
void printList(const ReservationList& ls){
for(int i = 0; i < ls.getLength(); i++){ std::cout<<"ls["<<i<<"]== "<<i+1<<ls.retrieve(i,i+1)<<std::endl; }
}
//main method
int main(){
ReservationList r;
std::cout<<"program starts!"<<std::endl;
std::cout<<"before printing empty list"<<std::endl;
printList(r);
std::cout<<"after printing empty list"<<std::endl;
std::cout<<"inserting starts!"<<std::endl;
r.insert(0,1);
std::cout<<"after inserting 1"<<std::endl;
r.insert(0,2);
std::cout<<"after inserting 2"<<std::endl;
r.insert(0,3);
std::cout<<"after inserting 3"<<std::endl;
r.insert(0,4);
std::cout<<"after inserting 4"<<std::endl;
r.insert(0,5);
std::cout<<"after inserting 5"<<std::endl;
printList(r);
return 0;
}
This the head of ReservationList class(ReservationList.h)
#ifndef RESERVATION_H
#define RESERVATION_H
#include <iostream>
class ReservationList {
public:
ReservationList();/*
ReservationList( const ReservationList& aList );
~ReservationList();*/
bool isEmpty() const;
int getLength() const ;
bool retrieve(int index, int resCode) const;
bool insert(int index, int resCode);
bool remove(int index);
private:
struct ReservationNode {
int Code;
ReservationNode* next;
};
int size;
ReservationNode *head;
ReservationNode *find(int index) const;
};
#endif
And these are the methods I have called so far constructor and insert methods
//empty constructor
ReservationList::ReservationList() {
head = NULL;
size = 0;
}
//insert method
bool ReservationList::insert(int index, int resCode) {
if(index < 0 || index > size) { return 0; }
//making node to be added
ReservationNode* tmp;
std::cout<<"inside insert 1"<<std::endl;
tmp->Code = resCode;/*mistake is hear */
std::cout<<"inside insert 2"<<std::endl;
tmp->next = NULL;
std::cout<<"inside insert 3"<<std::endl;
if ( (index == 0) && (size == 0) ) {
std::cout<<"inside insert 4"<<std::endl;
head = tmp;
size++;
return 1;
}
else if ( (index == 0) && (size == 1) ){
tmp->next = head;
head = tmp;
size++;
return 1;
}
ReservationNode *curr , *prev;
curr = find( index );
prev = find( index - 1 );
tmp->next = curr;
prev->next = tmp;
size++;
return 1;
}
This is the output
program starts!
before printing empty list
after printing empty list
inserting starts!
inside insert 1
[Done] exited with code=3221225477 in 0.622 seconds
with the "std::cout" i tracked the error it is at tmp->Code = resCode; part of the insert method
the problem is at after std::cout<<"inside insert 1"<<std::endl; however when I comment the tmp->Code = resCode; it gives error at the line just after. As I understand there is problem with accessing the variables inside struct or assigning them.
This code snippet
ReservationNode* tmp;
std::cout<<"inside insert 1"<<std::endl;
tmp->Code = resCode;/*mistake is hear */
std::cout<<"inside insert 2"<<std::endl;
tmp->next = NULL;
invokes undefined behavior because the pointer tmp is uninitialized and does not point to a valid object of the type ReservationNode.
It seems you forgot to call the operator new to create an object of the type ReservationNode.
Also calling the function find two times
ReservationNode *curr , *prev;
curr = find( index );
prev = find( index - 1 );
is inefficient.
The function can be defined simpler without a duplicated code.
bool ReservationList::insert( int index, int resCode )
{
bool success = not ( index < 0 || index > size );
if ( success )
{
ReservationNode **current = &head;
while ( index-- )
{
current = &( *current )->next;
}
ReservationNode *new_node = new ReservationNode { resCode, *current };
*current = new_node;
++size;
}
return success;
}
Pay attention to that it would be much better if the data member size will have the unsigned integer type size_t instead of the signed integer type int. The same is valid for the function parameter index.

C++ Hexadecimal Multiplication Segmentation Fault [closed]

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
Let me first start by saying I do not have access to debuggers and I'm using Nano as my editor
Currently, with my calculator, I am beating my head against a brick wall(segmentation fault). I've tried going through my pointers to discover what my problem is, but my lack of experience/knowledge has only gotten me so far. Let me explain what works so far in my program. Currently, I am able to store hexadecimal numbers in a linked list and add them together. The problem comes from my multiplication method.Somehow leftNode is becoming NULL midway through the multiplication method throwing a segmentation fault. I'm wondering at what point does leftNode become NULL?
Multiplication Method:
LList Calculator::multiply(LList& left, LList& right) {
LList prodSum;
listnode *leftNode = (left.next());
int zeros = 0;
for(;;) {
if(leftNode == NULL) break;
int lval = leftNode->data;
LList curList;
for(int i = 0; i < zeros; i++) {
curList.insertTail(0);
}
right.reset();
listnode *rightNode = (right.next());
int carry = 0;
while(rightNode != NULL) {
int rval = rightNode->data;
int product = lval * rval + carry;
carry = product / 16;
product %= 16;
curList.insertTail(product);
rightNode = (right.next());
}
while(carry) {
curList.insertTail(carry % 16);
carry /= 16;
}
prodSum = *add(prodSum, curList);
leftNode = (left.next()); // eventually causes a segmentation fault
leftNode->data << endl;
++zeros;
}
return prodSum;
}
Classes related to multiplication:
class listnode {
public:
element data;
listnode * next;
};
class LList {
private:
listnode * head;
listnode * tail;
listnode * view;
public:
LList();
~LList();
void read();
listnode* next();
void reset();
void print();
void insertTail(element val);
void clean();
element deleteHead();
};
class Calculator {
public:
Calculator();
//inline LList* add(LList& left, LList& right); works
inline LList multiply(LList& left, LList& right);
};
Calculator::Calculator() {
};
Other methods related to traversing nodes:
listnode* LList::next() {
listnode* temp = view;
if(temp != NULL)
view = view->next;
if(view == NULL) {
}
return temp;
};
void LList::reset() {
view = head;
}
LList::LList(){
head = NULL;
view = NULL;
};
void LList::insertTail(element val) {
listnode * temp;
temp = new listnode;
temp -> data = val;
temp -> next = NULL;
if(head == NULL) {
head = temp;
view = head;
}
else
tail -> next = temp;
tail = temp;
};
void LList::clean() {
while(head != NULL)
deleteHead();
};
element LList::deleteHead() {
listnode * temp;
temp = head;
head = head -> next;
delete temp;
return temp -> data;
};
LList::~LList(){
delete head;
};
it's me again.
One exception occurs after the line you marked: // eventually causes a segmentation fault, there seems to be a partially-formed line for sending leftNode->data to cout, but on the final iteration through left's nodes, leftNode = (left.next()); will set leftNode to NULL, so a dereference here might be causing the fault.
One other problem is that no copy constructor or assignment operator is defined for LList, so this line: prodSum = *add(prodSum, curList); will give prodSum a set of list nodes that will be deleted right after.
However, LList's destructor only seems to delete the head node, not the whole list, so there's a grab-bag of invalid and valid going on.
Also, multiply returns prodSum, so the lack of a copy constructor will make something similar happen.
I'm including a version of your code that seems to work. I had to make my own add function, just because I don't see it here.
I made the destructor delete all of the LList's nodes.
I marked the default copy constructor and assignment operator =delete because the default implementations do the wrong thing.
In order to pass LList objects around by value, I added a move constructor and a move assignment operator. These pass allocated nodes from one object to another, and only one object is allowed to keep one set of nodes, so you don't have to worry about double-destruction.
#include <iostream>
#include <string>
typedef int element;
class listnode {
public:
element data;
listnode * next;
};
class LList {
listnode *head, *tail, *view;
public:
LList() { head = view = tail = NULL; }
LList(LList&& src) : head(src.head), tail(src.tail), view(src.view) { src.head = src.tail = src.view = nullptr; }
LList(const LList&) = delete;
~LList() { clean(); }
LList& operator = (LList&& src) {
clean();
/* OK here */
head = src.head;
tail = src.tail;
view = src.view;
src.head = src.tail = src.view = nullptr;
return *this;
}
LList& operator = (const LList&) = delete;
listnode* next() {
listnode* temp = view;
if(temp) view = view->next;
return temp;
}
void reset() { view = head; }
void print();
void insertTail(element val) {
listnode* temp = new listnode;
temp->data = val;
temp->next = NULL;
if(!head) { view = head = temp; }
else { tail->next = temp; }
tail = temp;
}
void clean() { while(head) deleteHead(); }
element deleteHead() {
listnode* temp = head;
head = head->next;
const element data = temp->data;
delete temp;
return data;
}
};
LList add(LList& left, LList& right) {
LList sum;
int carry = 0;
left.reset();
right.reset();
for(;;) {
const listnode* leftNode = left.next();
const listnode* rightNode = right.next();
if(!leftNode && !rightNode) break;
if(leftNode) carry += leftNode->data;
if(rightNode) carry += rightNode->data;
sum.insertTail(carry % 16);
carry /= 16;
}
if(carry) sum.insertTail(carry);
return sum;
}
LList multiply(LList& left, LList& right) {
LList prodSum;
listnode *leftNode = left.next();
int zeros = 0;
for(;;) {
if(!leftNode) break;
int lval = leftNode->data;
LList curList;
for(int i = 0; i < zeros; i++) {
curList.insertTail(0);
}
right.reset();
listnode *rightNode = right.next();
int carry = 0;
while(rightNode) {
int rval = rightNode->data;
int product = lval * rval + carry;
carry = product / 16;
product %= 16;
curList.insertTail(product);
rightNode = right.next();
}
while(carry) {
curList.insertTail(carry % 16);
carry /= 16;
}
prodSum = add(prodSum, curList);
leftNode = left.next(); // eventually causes a segmentation fault
//std::cout << leftNode->data << std::endl;
++zeros;
}
return prodSum;
}
LList string_to_list(std::string hex_string) {
LList list;
for(size_t i=hex_string.length()-1; i+1; --i) {
char c = hex_string[i] | 0x20;
if (c >= '0' && c <= '9') list.insertTail(c - '0');
else if(c >= 'a' && c <= 'f') list.insertTail(c - 'a' + 10);
}
return list;
}
std::string list_to_string(LList& list) {
std::string hex_string;
list.reset();
for(;;) {
listnode* node = list.next();
if(!node) return hex_string;
static const char digits[] = "0123456789abcdef";
hex_string = digits[node->data] + hex_string;
}
}
int main() {
//LList list = string_to_list("1234aBcd");
//std::string s = list_to_string(list);
//std::cout << s << '\n';
LList left = string_to_list("111");
LList right = string_to_list("333");
LList prod = multiply(left, right);
std::cout << list_to_string(prod) << '\n';
}

linked list with data in null node

i want to make a linked list ..
but the first node with a data and null link
if i input a string (123)
linked list be like this:
1/null - 2/point to the last one(1) - 3/point to the last one(2)
#include <iostream>
#include <string>
using namespace std;
struct link
{
int data;
link* next;
};
class LinkedList
{
private:
link* first;
public:
LinkedList(){}
void Add(string s)
{
for (int i = 0; i > s.length(); i++)
{
if (i == 0)
{
first->data = s[i];
first->next = NULL;
}
else
{
link* NewOne = new link;
NewOne->data = s[i];
NewOne->next = first;
first = NewOne;
}
}
}
void display()
{
cout << first->data;
}
};
int main()
{
LinkedList l1;
l1.Add("2734");
l1.display();
return 0;
}
what's the wrong in the code
You forget to allocate memory for first.
Following may help (using std::unique_ptr for free/correct memory management):
struct link{
char data;
std::unique_ptr<link> next;
};
class LinkedList {
private:
std::unique_ptr<link> first;
public:
void Set(const std::string& s){
for (auto c : s) {
std::unique_ptr<link> node = std::move(first);
first = std::make_unique<link>();
first->data = c;
first->next = std::move(node);
}
}
Live example
It also looks like you're storing characters in an int. Your output will be the ASCII value of the character rather than the raw int values.
I would recommend using unique pointers as Jarod42 has done. Having said that, this quick example below does not use them so you will need to call delete appropriately or use unique_ptr.
I added a last pointer to help traversal of the list as we make new links.
private:
Link * first;
Link *last;
int numLinks;
public:
LinkedList()
{
first = NULL;
last = NULL;
numLinks = 0;
}
Now for Add
void Add(string s)
{
for (int i = 0; i < s.length(); i++)
{
if (numLinks == 0)
{
first = new Link;
first->data = (s[i] - '0');
first->next = NULL;
last = first;
numLinks++;
}
else
{
Link * newLink = new Link;
newLink->data = (s[i] - '0');
newLink->next = NULL;
last->next = newLink;
last = newLink;
numLinks++;
}
}
}
The constructor does not initialize the first member. Subsequently, in Add():
for (int i = 0; i > s.length();i++){
if (i == 0){
first->data = s[i];
first->next = NULL;
}
This ends up dereferencing an uninitialized pointer, leading to undefined behavior.
There's also a problem with your display() too, but this is the main problem.

Hash-table - Array of Linked-list - C++

I'm trying to create a Hash-table by using an array on linked-nodes (making a linked list).
But I'm having difficulties inserting a value into the Hash-table. When I run it, I get this:
http://gyazo.com/3a28a70e66b3ea34e08223e5948f49c0.png
Here is my code:
#include <iostream>
using namespace std;
class Node {
public:
int num;
Node * next;
};
class intHashTable {
private:
int size;
Node ** table;
public:
intHashTable(int size); // construct a new hash table with size elements
~intHashTable(); // delete the memory for all internal components
void insert(int num); // insert num into the hash table, no effect
// if num is already in table
void remove(int num); // remove num from the hash table, no effect if not in table
int lookup(int num); // return 1 if num is already in table, 0 otherwise
void print(void); // print the elements of the hash table to the screen
};
// construct a new hash table with nelements elements
intHashTable::intHashTable(int nelements)
{
size = nelements;
table = new Node*[size];
for ( int i = 0; i < size; i++ ) {
table[i] = NULL;
}
}
intHashTable::~intHashTable()
{
for(int i=0; i<size; i++)
{
Node* temp = table[i];
while(temp != NULL)
{
Node* next = temp->next;
delete temp;
temp = next;
}
}
size = 0;
delete[] table;
}
void intHashTable::insert(int num){
int location = ((unsigned)num) % size;
Node *runner = table[location];
if(runner == NULL ){
runner->num = num;
}else{
while(runner != NULL ){
runner = runner->next;
}
runner->num = num;
}
}
int main(){
intHashTable a (10);
a.insert(2);
return 0;
}
After construction of intHashTable, all the elements of table are still NULL. However, in the function insert, one element is dereferenced:
Node *runner = table[location];
runner = runner->next;
This makes the program crash, because it is illegal to dereference a null pointer.
the logic here is wrong
int location = ((unsigned)num) % size;
Node *runner = table[location];
if(runner == NULL ) // if null u dereference it!
{
runner->num = num;
}
else
{
while(runner != NULL ) { // u loop until null
runner = runner->next;
}
runner->num = num; // once u reach null u dereference it!
}
i would suggest instead:
first a ctor for your Node
class Node {
public:
int num;
Node * next;
Node( int _n ) : num(_n), next(NULL) { }
};
and then
if ( runner != NULL )
{
while ( runner->next != NULL )
{
runner = runner->next;
}
runner->next = new Node( num );
}
else
{
table[location] = new Node( num );
}
This code certainly won't work:
if(runner == NULL ){
runner->num = num;
If runner is NULL, then you should never dereference it (using * or -> on it).
Node *runner = table[location];
runner = runner->next;
if(runner == NULL )
You never verified whether table[location] is null. But during construction of your hashtable, there are no nodes inside the node table (you set yourself every entry to null).
The problem with your code is that you never think about allocating your node. You should be doing
Node* toInsert = new Node;
toInsert->next= NULL;
toInsert->num = num;
if(table[location]==NULL){
table[location] = toInsert;
}
else{
Node *runner = table[location];
while(runner->next != NULL){
runner = runner->next;
}
runner->next = toInsert;
}

C++ doesn't save the changes by other method

I'm trying to implement a linked list class in C++ and I got problem. I have the += operator who adds new node.
the linked list class interface:
template <typename Type>
class LinkedList {
public:
LinkedList<Type>* head;
// linked list stracture
Type data;
LinkedList<Type>* next;
// others ....
size_t length;
public:
LinkedList();
~LinkedList();
void initializeHead(LinkedList<Type>* headPtr);
size_t size() const;
LinkedList& operator+=(const Type& add);
void operator-=(const Type& remove);
LinkedList<Type>& operator[] (const size_t index) const;
bool operator== (const LinkedList<Type> &versus) const;
friend ostream& operator<< (ostream& out,LinkedList& obj);
};
and here i have the += overload implement:
template <typename Type> LinkedList<Type>& LinkedList<Type>::operator +=(const Type& add) {
// head ptr - :)
LinkedList<Type>* p = head->next;
// go to the end
while(p) p = p->next;
// now on end - create new..!!!
try {
p = new LinkedList<Type>;
} catch (bad_alloc& e) {
cout << "There\'s an allocation error....";
} catch (...) {
cout << "An unknown error.." << endl;
}// fill and done
p->data = add;
p->next = NULL;
// increment length .........
++head->length;
// done ............
return *p;
}
Additionally , I have "array" access overload method:
template <typename Type> LinkedList<Type>& LinkedList<Type>::operator [](const size_t index) const {
if(index < 0 || index >= length) // invaild argument
throw exception();
// continue
LinkedList<Type>* p = head;
for(size_t i = 0; i < index; ++i) p = p->next; // we are at what we want
return *p;
}
All works correctly - I checked on the dibugger,
the problem is - += doesn't save the new node in "head->next", for some reason, after finish += method, head->next equal to null.
Do someone know why the new allocation don't link to head->next?
Thanks a lot!!
after while(p) p = p->next; p is NULL
and next you do p = new LinkedList<Type>; but you don't link the p into the head.
Instead of:
// go to the end
while(p) p = p->next;
You need:
head->next = p;
As the other answers say, you go beyond the list when you try to add. Try something like this:
template <typename Type> LinkedList<Type>& LinkedList<Type>::operator +=(const Type& add)
{
LinkedList<Type> *last;
// Find the last node in the list
for (last = head; last != 0 && last->next != 0; last = last->next)
{
}
// `last` now points to the last node in the list, or is zero
// If zero (i.e. NULL) then list is empty
if (last == 0)
{
head = new LinkedList<Type>;
head->next = 0;
head->data = add;
head->length = 0;
}
else
{
last->next = new LinkedList<Type>;
last->next->next = 0;
last->next->data = add;
}
// We can safely use `head` as we are sure it won't be zero
head->length++;
// Return the added node
return (last != 0 ? *last->next : *head);
}
You can also use temporary variable to store last node and then the last node will point to new node.
This is sample code. You need to take care of some situations like adding first node etc.
LinkedList<Type>* temp = NULL;
while(p)
{
temp = p;
p = p->next;
}
try
{
p = new LinkedList<Type>;
temp->next = p;
}