Redefine a Node of linked list: std::string - c++

I am currently working on a school project, the material is new to me at the moment, basically, we are creating a Robot Guider that tracks their movement, distance, speed, etc... one of the functions that we are required to make is renaming a robot, however, they are stored in Node.
I have spent some time looking around for a quick solution and I am a little confused by the examples online. If someone could please help but also explain their logic that would be greatly appreciated.
we are using two different classes to track all of the information
-----CLASS #1:
#ifndef RobotList_hpp
#define RobotList_hpp
#include "Robot.hpp"
#include <stdio.h>
#include <iostream>
class RobotList{
private:
class Node{
public:
Robot* val;
Node* next = nullptr;
Node(std::string aName) {
val = new Robot;
val->setName(aName);
}
};
Node* head = nullptr;
Node* tail = nullptr;
public:
RobotList() = default;
~RobotList();
void display() const;
bool isEmpty();
Robot* find_nth();
void updateList();
void addNode(std::string name);
void deleteNode(std::string name);
void rename();
void robotDist() const;
};
#endif /* RobotList_hpp */
---CLASS #2:
#ifndef Robot_hpp
#define Robot_hpp
#include <stdio.h>
#include <iostream>
#include <algorithm>
class Robot{
private:
int x, y, curSpeed, totDist;
std::string name; char lastCommand;
bool stop_; int off_or_on;
public:
std::string getName() { return name; }
void setName(std::string a) {
this->name = a;
}
int getTotDist() { return totDist; }
void moveRobot();
int findRobot();
};
#endif /* Robot_hpp */
void RobotList::rename(){
std::string new_name;
std::cout << "Which robot do you want to rename?"<< std::endl;
std::cin >> new_name;
Node* temp = head;
while(!head){
if(temp->val->getName() == new_name){
// update list with user input new_name
// reassign a node that holds a string value
}
}
temp = temp->next; // rest of list til nullptr
}
This is what I tried to do but it was not operating properly.
I wrote out two comments on what I am trying to do. Thanks.

The problem is the while loop.
Head is a pointer to the first element so !head is true only when the list is empty, which is not what you want. Head should not be modified because we will lose the start of the list, that's why we have the temp.
The loop should stop at the end of the list, we know we reached the end when temp is nullptr. This is convenient because it makes sure we never dereference a null pointer. temp = temp->next; should be placed inside the loop so that it doesn't get stuck at the first element.
std::string old_name, new_name;
std::cout << "Which robot do you want to rename?"<< std::endl;
std::cin >> old_name; // name to search for
std::cout << "Enter new name:"<< std::endl;
std::cin >> new_name; // new name for the robot with old_name
Node* temp = head; // temp = first element(node) of the list
while(temp){ // while we haven't reached the end of the list
if(temp->val->getName() == old_name){
temp->val->setName(new_name);
break; // break if you only want to modify the first occurrence
}
temp = temp->next; // move to the next node
}
Also try to use const references for passing objects whenever possible, otherwise you create a lot of unwanted copies.

Related

Assigning pointer

I have been working on this for a while and cannot seem to understand what is happening. I am trying to take the values in istr, put them in a linked list and sort them alphabetically. Eventually I will print them out. I am not sure where my problem is but I thought it was in the function InsertAfter. Is this not my problem and if so do you know what may be causing my linked list to not link? The last bit of code only outputs the headObj and not all of them, so I assumed that my list wasn't linking properly in nextNodePtr in each object but I am not sure. Thank you for your help!
void WordNode::InsertAfter(WordNode* nodeLoc) {
WordNode* tmpNext = 0;
tmpNext = this->nextNodePtr; // Remember next
this->nextNodePtr = nodeLoc; // this -- node -- ?
nodeLoc->nextNodePtr = tmpNext; // this -- node -- next
return;
}
wordNode.hpp
#ifndef wordNode_hpp
#define wordNode_hpp
#include <stdio.h>
#include <iostream>
#include <sstream>
#include <string>
using namespace std;
class WordNode {
public:
WordNode(string wordval = "", int count = 0, WordNode* nextLoc = 0);
void InsertAfter(WordNode* nodePtr);
WordNode* GetNext();
void PrWordNodeData();
string GetWord();
private:
string word;
WordNode* nextNodePtr;
int wordCount;
};
wordNode.cpp
#include "wordNode.hpp"
// Constructor
WordNode::WordNode(string wordval,int count, WordNode* nextLoc) {
this->word = wordval;
this->wordCount = count;
this->nextNodePtr = nextLoc;
return;
}
/* Insert node after this node.
* Before: this -- next
* After: this -- node -- next
*/
void WordNode::InsertAfter(WordNode* nodeLoc) {
WordNode* tmpNext = 0;
tmpNext = this->nextNodePtr; // Remember next
this->nextNodePtr = nodeLoc; // this -- node -- ?
nodeLoc->nextNodePtr = tmpNext; // this -- node -- next
return;
}
// Print dataVal
void WordNode::PrWordNodeData() {
cout << this->word <<": count=" <<this->wordCount << endl;
return;
}
// Grab location pointed by nextNodePtr
WordNode* WordNode::GetNext() {
return this->nextNodePtr;
}
//Returns word
string WordNode::GetWord()
{
return word;
}
main.cpp
#include <iostream>
#include <sstream>
#include <string>
#include "wordNode.hpp"
int main() {
WordNode* headObj = 0; // Create WordNode objects
WordNode* currObj = 0;
WordNode* nextObj = 0;
string istr ="555 999 777 333 111";
istringstream instring(istr);
string temp;
//Assigns first word to the head object
if (!instring.eof()){
instring >> temp;
headObj=new WordNode(temp,1);
}
currObj=headObj;
while (!instring.eof()){
instring >> temp;
nextObj=new WordNode(temp,1);
//swaps values if currObj is greater than the next word
if(currObj > nextObj) {
currObj->InsertAfter(nextObj);
}
currObj=nextObj;
}
// Print linked list
currObj = headObj;
while (currObj != 0) {
currObj->PrWordNodeData();
currObj = currObj->GetNext();
}
string i;
cin >> i;
return 0;
}
In the very first iteration of the loop (using the string you gave as example) you loose the reference to the head object and hence subsequent iterations will add nodes to a "headless list".
currObj=headObj;
while (!instring.eof()){
instring >> temp;
nextObj = new WordNode(temp,1);
//swaps values if currObj is greater than the next word
if(currObj->GetWord() > nextObj->GetWord()) {
currObj->InsertAfter(nextObj);
}
// And what happens if it is not greater?
currObj = nextObj; // Loose reference to head here if not greater
}
To fix your code you will either just have to add all nodes to the list and then sort it with a sorting algorithm or insert them on the fly as you intend to do now. However, to do the latter you will have to modify your insertion logic, i.e. insert node at the beginning (if new node is alphabetically lower than the first element) or at the end. I recommend reading this nice article about singly linked lists. It has examples and code for the insertions mentioned.

Hash table implementation in C++

I am trying the following code for Hash table implementation in C++. The program compiles and accepts input and then a popup appears saying " the project has stopped working and windows is checking for a solution to the problem. I feel the program is going in the infinite loop somewhere. Can anyone spot the mistake?? Please help!
#include <iostream>
#include <stdlib.h>
#include <string>
#include <sstream>
using namespace std;
/* Definitions as shown */
typedef struct CellType* Position;
typedef int ElementType;
struct CellType{
ElementType value;
Position next;
};
/* *** Implements a List ADT with necessary functions.
You may make use of these functions (need not use all) to implement your HashTable ADT */
class List{
private:
Position listHead;
int count;
public:
//Initializes the number of nodes in the list
void setCount(int num){
count = num;
}
//Creates an empty list
void makeEmptyList(){
listHead = new CellType;
listHead->next = NULL;
}
//Inserts an element after Position p
int insertList(ElementType data, Position p){
Position temp;
temp = p->next;
p->next = new CellType;
p->next->next = temp;
p->next->value = data;
return ++count;
}
//Returns pointer to the last node
Position end(){
Position p;
p = listHead;
while (p->next != NULL){
p = p->next;
}
return p;
}
//Returns number of elements in the list
int getCount(){
return count;
}
};
class HashTable{
private:
List bucket[10];
int bucketIndex;
int numElemBucket;
Position posInsert;
string collision;
bool reportCol; //Helps to print a NO for no collisions
public:
HashTable(){ //constructor
int i;
for (i=0;i<10;i++){
bucket[i].setCount(0);
}
collision = "";
reportCol = false;
}
int insert(int data){
bucketIndex=data%10;
int col;
if(posInsert->next==NULL)
bucket[bucketIndex].insertList(data,posInsert);
else { while(posInsert->next != NULL){
posInsert=posInsert->next;
}
bucket[bucketIndex].insertList(data,posInsert);
reportCol=true;}
if (reportCol==true) col=1;
else col=0;
numElemBucket++;
return col ;
/*code to insert data into
hash table and report collision*/
}
void listCollision(int pos){
cout<< "("<< pos<< "," << bucketIndex << "," << numElemBucket << ")"; /*codeto generate a properly formatted
string to report multiple collisions*/
}
void printCollision();
};
int main(){
HashTable ht;
int i, data;
for (i=0;i<10;i++){
cin>>data;
int abc= ht.insert(data);
if(abc==1){
ht.listCollision(i);/* code to call insert function of HashTable ADT and if there is a collision, use listCollision to generate the list of collisions*/
}
//Prints the concatenated collision list
ht.printCollision();
}}
void HashTable::printCollision(){
if (reportCol == false)
cout <<"NO";
else
cout<<collision;
}
The output of the program is the point where there is a collision in the hash table, thecorresponding bucket number and the number of elements in that bucket.
After trying dubbuging, I come to know that, while calling a constructor you are not emptying the bucket[bucketIndex].
So your Hash Table constructor should be as follow:
HashTable(){ //constructor
int i;
for (i=0;i<10;i++){
bucket[i].setCount(0);
bucket[i].makeEmptyList(); //here we clear for first use
}
collision = "";
reportCol = false;
}
//Creates an empty list
void makeEmptyList(){
listHead = new CellType;
listHead->next = NULL;
}
what you can do is you can get posInsert using
bucket[bucketIndex].end()
so that posInsert-> is defined
and there is no need to
while(posInsert->next != NULL){
posInsert=posInsert->next;
because end() function is doing just that so use end() function

Unique pointer in Linked List - Unhandled exception, stack overflow

First of all, let me say thank you for all the help I've been received in the last couple hours. I've been struggle with this problem, how to convert from raw pointer to unique pointer and got myself into a lot of errors. However, with the help of this community, I've been thankful that my program finally compiles without errors at all. But I'm not there yet, I guess. I feel like I'm like one minute away from the finish line, so I won't give up till I can solve it. My program crashes as soon as it runs, it says stack overflow and throw out the exception. I guess it must be the way that I declare and initialize the unique pointer as a class member in the constructor is not correct at all and therefore it crashes right from the minute it calls the constructor. Would anyone please tell me what I should do to fix this error ? Thanks.
This is my main cpp file:
#include"ContactList.h"
#include<memory>
using namespace std;
int main()
{
//ContactList* cl1 = new ContactList();
unique_ptr<ContactList> cl1(new ContactList());
string name;
while(true)
{
cout << "Enter a name or q to quit: " << endl;
cin >> name;
if(name == "q")
break;
cl1->addToHead(name);
}
cl1->PrintList();
return 0;
}
ContactList.h
#pragma once
#include"Contact.h"
#include<memory>
using namespace std;
class ContactList
{
public:
ContactList();
void addToHead(const std::string&);
void PrintList();
private:
//Contact* head;
unique_ptr<Contact> head;
int size;
};
ContactList.cpp
#include"ContactList.h"
#include<memory>
using namespace std;
ContactList::ContactList(): head(new Contact()), size(0)
{
}
void ContactList::addToHead(const string& name)
{
//Contact* newOne = new Contact(name);
unique_ptr<Contact> newOne(new Contact(name));
if(head == 0)
{
head.swap(newOne);
//head = move(newOne);
}
else
{
newOne->next.swap(head);
head.swap(newOne);
//newOne->next = move(head);
//head = move(newOne);
}
size++;
}
void ContactList::PrintList()
{
//Contact* tp = head;
unique_ptr<Contact> tp(new Contact());
tp.swap(head);
//tp = move(head);
while(tp != 0)
{
cout << *tp << endl;
tp.swap(tp->next);
//tp = move(tp->next);
}
}
Contact.h
#pragma once
#include<iostream>
#include<string>
#include<memory>
class Contact
{
friend std::ostream& operator<<(std::ostream& os, const Contact& c);
friend class ContactList;
public:
Contact(std::string name = "none");
private:
std::string name;
//Contact* next;
std::unique_ptr<Contact> next;
};
Contact.cpp
#include"Contact.h"
using namespace std;
Contact::Contact(string n):name(n), next(new Contact())
{
}
ostream& operator<<(ostream& os, const Contact& c)
{
return os << "Name: " << c.name;
}
This is the error I get:
Unhandled exception at 0x77E3DEFE (ntdll.dll) in Practice.exe: 0xC00000FD: Stack overflow (parameters: 0x00000001, 0x002B2F58).
You didn't post the code for Contact, but I assume it's the same as in one of your previous questions:
Contact::Contact(string n):name(n), next(new Contact())
{
}
As you can see, constructing a Contact requires setting its next member to a new Contact.
In order to construct that Contact, you're going to create a new Contact for its next member.
And so on, et cetera, to infinity and beyond.
This is the cause of of the stack overflow - Contact construction never ends.
You probably don't want next to be anything in particular for a newly constructed Contact, so try
Contact::Contact(string n):name(n), next(0)
{
}
You have a problem in your ContactList::PrintList() method: you don't need unique_ptr when you iterate through some items just observing them.
When observing items, raw pointers are just fine.
In general, owning raw pointers are not good (except in some special cases), but observing raw pointers are just fine.
In addition, note also that in your ContactList default constructor, you don't need to allocate an empty Contact with new and assign it to head unique_ptr data member: unique_ptr default constructor will automatically initialize head to a nullptr.
Note also that the ContactList::PrintList() methods should be marked as const for proper const-correctness, since usually printing the content of some collection should not alter the items in the collection.
Finally, the ContactList allocation in your main() function can be simply done on the stack:
ContactList cl;
There's no need to use unique_ptr in this case (please program in C++, not in Java or C# style).
And, a style note: I don't like that some methods start with upper-case letter (e.g. PrintList()) and others with lower-case letter (e.g. addToHead()): choose one style, and be coherent with it (at list at the source file level, if not at the whole project level).
Below there's a single source file test code, based on your code with some fixes applied.
I compiled it and tested a bit with VC10 (Visual Studio 2010 SP1); it seems to work:
C:\Temp>test.exe
Enter a name or q to quit:
Bob
Enter a name or q to quit:
Jane
Enter a name or q to quit:
John
Enter a name or q to quit:
Mary
Enter a name or q to quit:
q
[Contact name: Mary]
[Contact name: John]
[Contact name: Jane]
[Contact name: Bob]
Compilable source code follows:
#include <iostream>
#include <memory>
#include <ostream>
#include <string>
using namespace std;
// "Imaginary" Contact implementation (you didn't provide it)
struct Contact {
Contact() {}
explicit Contact(const string& n) : name(n) {}
string name;
unique_ptr<Contact> next;
};
ostream& operator<<(ostream& os, const Contact& c) {
os << "[Contact name: " << c.name << "]";
return os;
}
class ContactList {
public:
ContactList();
void AddToHead(const string&);
void PrintList() const;
private:
unique_ptr<Contact> head;
int size;
};
ContactList::ContactList()
: size(0) {
// No need to initialize head pointer.
// It will be automatically initialized to nullptr.
}
void ContactList::AddToHead(const string& name) {
unique_ptr<Contact> newOne(new Contact(name));
if(head == 0) {
head.swap(newOne);
} else {
newOne->next.swap(head);
head.swap(newOne);
}
size++;
}
void ContactList::PrintList() const {
const Contact * pContact = head.get();
while (pContact != nullptr) {
cout << *pContact << endl;
pContact = pContact->next.get();
}
}
int main() {
// No need to allocate ContactList using unique_ptr.
// Stack scoped-based allocation is just fine.
ContactList cl;
while (true) {
cout << "Enter a name or q to quit: " << endl;
string name;
cin >> name;
if (name == "q")
break;
cl.AddToHead(name);
}
cl.PrintList();
}

C++ Pointer target returning wrong value

I am a fairly experience C# programmer and trying to help out a friend with a C++ application that creates a Stack object. It has been well over 13 years since I've even seen C++ and I am having a damn fine time trying to recall the proper way to do this. It took me a bit to get up to speed on the Header/CPP distinction again, so there may be issues in there even. Here is my problem:
//Stack.h
#ifndef __STACK_INCLUDED__
#define __STACK_INCLUDED__
#include "Node.h"
class Stack
{
private:
/// Going to be the pointer to our top node
Node* m_topNode;
/// Running count of elements
int m_count;
public:
///Constructor
Stack();
///Allows us to retrieve the top value from the stack
/// and remove it from the stack
int Pop();
.
.
.
};
#endif
Below is the CPP that matches the header. I am doing in here JUST for debugging at the moment. I am also fully qualifying everything because I was not sure if that is causing issues with the pointers and loss of references.
//Stack.cpp
#include "stdafx.h"
#include "Stack.h"
#include <iostream>
Stack::Stack(){
m_count = 0;
m_topNode = NULL;
}
void Stack::Push(int Value){
std::cout << "\nPushing Value: ";
std::cout << Value;
std::cout << "\n";
if ( Stack::m_topNode )
{
std::cout << "TopNode Value: ";
std::cout << Stack::m_topNode->data;
std::cout << "\n";
}
std::cout << "\n";
Node newNode(Value, NULL, Stack::m_topNode);
Stack::m_topNode = &newNode;
Stack::m_count++;
}
The node class is a pretty simple entity. Just needs to store a value and the pointers on either side. I know I don't need to track in both directions for a Stack but I wanted to make this something that was easily changed to a Queue or similar construct.
//Node.h
#ifndef __NODE_INCLUDED__
#define __NODE_INCLUDED__
class Node
{
private:
public:
///Constructor allows us to specify all values.
/// In a stack I expect NextNode to be NULL
Node(int Value,Node* NextNode, Node* PreviousNode);
///Pointer to the next node
Node* Next;
///Pointer to the previous node
Node* Prev;
///Value to be stored
int data;
};
#endif
Very simple implementation:
//Node.cpp
#include "stdafx.h"
#include "Node.h"
Node::Node(int Value, Node* NextNode, Node* PreviousNode){
data = Value;
Next = NextNode;
Prev = PreviousNode;
}
My main is just about sending 2 values to the stack right now via Push and seeing what the values are printing:
#include "stdafx.h"
#include "Node.h"
#include "Stack.h"
using namespace std;
int main(){
Stack s = Stack();
for ( int i = 0; i < 2; i++ ){
s.Push(i * 10);
}
int blah;
cin >> blah; //Stall screen
return 0;
}
Here is the Output:
Pushing Value: 0
<blank line>
Pushing Value: 10
TopNode Value: -858993460
When I hit Node newNode(Value, NULL, Stack::m_topNode) in the debugger I can see it tracking the proper value in the current node, but m_topNode references a really odd value. I'm hoping it's very obvious that I'm doing something dumb as I don't remember this being this tricky when I did it years ago. Appreciate any help/insight to my incorrect manners.
Node newNode(Value, NULL, Stack::m_topNode);
Stack::m_topNode = &newNode;
Stack::m_count++;
This is your problem. You allocate the new node on the current stack, and then put the pointer into the linked list of nodes. This pointer will be invalid as soon as your stack frame returns, and all hell breaks lose. ;)
You need to allocate the node with new.
As stated by Norwæ, you need to allocate your newNode with "new" because if you dont, your newNode is static and will be out of scope at the end of the Push function.
You also need to call your private members without the "Stack::" as this is used in C++ only to access static class members and functions. replace "Stack::m_topNode" for "m_topNode" only, and Stack::m_count for m_count.
Here is a working Push function :
void Stack::Push(int Value){
std::cout << "\nPushing Value: ";
std::cout << Value;
std::cout << "\n";
if ( m_topNode )
{
std::cout << "TopNode Value: ";
std::cout << m_topNode->data;
std::cout << "\n";
}
std::cout << "\n";
Node * newNode = new Node(Value, NULL, m_topNode);
m_topNode = newNode;
m_count++;
}
This line:
std::cout << Stack::m_topNode->data;
happens before
Node newNode(Value, NULL, Stack::m_topNode);
Stack::m_topNode = &newNode;
Stack::m_count++;
So you're trying to print an uninitialized value. Reverse these and see what happens.

C++ Stack Push/Print Implementation

I'm trying to make a stack implementation in C++ but when I try to print the stack,
it just prints the first element instead of the whole stack.
I've tested it and I'm pretty sure that my Push function is right, but I'm not sure.
#include <stdio.h>
#include <stdlib.h>
#include "stack.h"
int main(){
StackElement *stack = new StackElement();
stack->data = 20;
stack->Push(30,stack);
stack->Push(40,stack);
stack->Print(stack);
}
#include <stdio.h>
#include <stdlib.h>
class StackElement{
public:
int data;
StackElement* next;
StackElement();
void StackElement::Push(int value, StackElement *oldElement);
void StackElement::Print(StackElement *element);
};
StackElement::StackElement(){
next = NULL;
}
void StackElement::Push(int value, StackElement *oldElement){
StackElement *newElement = new StackElement();
newElement->data = value;
printf("Element added to stack: %d\n", newElement->data);
oldElement->next = newElement;
}
void StackElement::Print(StackElement *element){
while(element->next != NULL){
printf("%d\n",element->data);
element = element->next;
}
}
Your code kept loosing the previous pushed element, leaking memory, as #Beta described.
I suggest comparing my code below to your code. You'll see, I've moved the handling of the stack elements outside, just to be able to keep track of the first element. Also, notice that there is no pointer in the main function. That is what we expect from a class.
Stack_element is a struct really as there's not much point in making the Stack_element itself encapsulated, it is just an implementation detail of Stack.
So here's my code derived from yours
#include<iostream>
struct Stack_element{
int data;
Stack_element*next;
};
class Stack{
private:
Stack_element*last_data, first_data;
public:
Stack():last_data(NULL), first_data(NULL){}
void push(int data);
void print() const;
};
void Stack::push(int data)
{
Stack_element*p=new Stack_element();
p->data=data;
p->next=NULL;
if(last_data)
last_data->next=p;
else // empty stack
first_data=p;
last_data=p;
}
void Stack::print()
{
for(Stack_element*p=first_data;p;p=p->next)
std::cout << p->data << std::endl; // ** Do not use printf in c++. Ever. **
}
and in the main function just call
Stack stack;
stack.push(30);
stack.push(40);
stack.print();
REMARK: For a C++ish print you might want to do an ostream& print(ostream& os) instead, where
std::ostream& Stack::print(std::ostream& os)
{
for(Stack_element*p=first_data;p;p=p->next)
os << p->data << std::endl;
return os;
}
just to be able to write std::cout << stack.print() << std::endl;. The benefit of this is that you can easily redirect to a file.
std::ofstream ofs("yourfile.txt");
ofs << stack.print() << std::endl; // prints to file instead of screen.
Suppose this much works as planned:
StackElement *stack = new StackElement();
stack->data = 20;
stack->Push(30,stack);
Now your data looks like [20]->[30]
Now you attempt
stack->Push(40,stack);
So the Push method creates a new StackElement, gives it the value 40, and sets Stack to point to it: [20]->[40]. Notice that [30] has been lost.
Then the Print function:
while(element->next != NULL){
printf("%d\n",element->data);
element = element->next;
}
If there is only one element (whose next is NULL), this function will quit and print nothing. If there are two, this function will print the data of the first, then quit. And there will never be more than two, as long as Push has that bug.