cardealership with dead end - Endless loop and no solution - c++

I just can't seem to figure out why my code doesn't work.
My program is about reading two text files representing a cardealership, and putting the input into a linked list or an STL list depending on mode. Then the orders are read and depending on the availability an error log is created.
The thng is that it keeps on looping in the linked list mode and that is doesn't seem to write the error log.
I feel pretty stupid about this. I don't want you guys to solve the error but teach me how to do it. I'm thankful for any review of my code by more experienced people.
I've tried debugging in Eclipse in XCode and in VS2012(VM with Win8). In none of the IDEs the variables are shown in the debug editor which I just don't understand. I use the MacOSX GCC Compiler.
So here are the txt files:
input.txt
Brera 3
Golf 5
Punto 13
Fiesta 19
and orders.txt
323 Brera 1
324 Golf 6
354 Punto 3
337 Gobldibock 1
this is my main method:
// file main.cpp
#include "cardealership.hpp"
#include <fstream>
#include <iostream>
#include <sstream>
#include <string>
int main( int argc, char* argv[] ) {
std::cout << "argv[2]: " << argv[2] << "\n";
std::cout << "argv[3]: " << argv[3] <<"\n";
const unsigned int mode = atoi( argv[1]);
std::string arg2 = argv[2];
std::string arg3 = argv[2];
cardealership* dealer = new cardealership(arg2, arg3, mode);
std::cout << "dealership created" << "\n";
dealer->readInputFileToList();
std::cout << "still running" << "\n";
dealer->readOutputFileAndAlterInventory();
std::cout << "finishing" << "\n";
return 0;
}
Here are the header of the class containing the actual lists:
// file cardealership.hpp
#ifndef CARDEALERSHIP_HPP // prevent multiple inclusions
#define CARDEALERSHIP_HPP
#include <string>
#include <list>
#include <vector>
typedef struct linkedNode
{
char* data; // will store information
int amountOfCars;
linkedNode* next; // the reference to the next node.
};
class cardealership
{
public:
cardealership (std::string inputFile, std::string ordersFile, const unsigned int mode);
~cardealership();
void readInputFileToList();
void readOutputFileAndAlterInventory();
void printInventory (); //TODO
private:
const unsigned int mode;
std::string inputFile;
std::string ordersFile;
std::list<linkedNode*> listOfCars; //Using Linked Node without linking them...
std::vector<linkedNode*> linkedListOfCars;
};
#endif
and the footer:
// file cardealership.cpp
#include "cardealership.hpp"
#include <iostream>
#include <cstring>
#include <fstream>
#include <sstream>
cardealership::cardealership(std::string inputFile, std::string ordersFile, const unsigned int mode)
: inputFile(inputFile),
ordersFile(ordersFile),
mode(mode)
{}
cardealership::~cardealership()
{
listOfCars.clear();
linkedListOfCars.clear();
}
void cardealership::readInputFileToList(){
std::ifstream infile;
std::string line;
infile.open(inputFile.c_str(),
std::ifstream::in);
if (!infile.good()){
std::cout << "Na na na Input File" << "\n";
}
linkedNode* previousNode;
while(getline(infile, line)){
char* model;
int amountOfCars;
linkedNode* tmpNode;
std::stringstream helperStream;
getline(infile, line);
helperStream << line;
helperStream >> model;
helperStream >> amountOfCars;
//Test
std::cout << "Line: " << line << std::endl;
std::cout << model << ", " << amountOfCars << std::endl;
tmpNode->data = model;
tmpNode->amountOfCars = amountOfCars;
if (mode == 0) { //Use linked list
if(previousNode != NULL){
previousNode->next = tmpNode; //Link that shit
previousNode = tmpNode;
linkedListOfCars.push_back(tmpNode);
}
else{
linkedListOfCars.push_back(tmpNode);
}
}
else if (mode == 1){ //Use STL list
listOfCars.push_back(tmpNode);
}
else{
std::cout<< "invalid mode" << std::endl;
}
if (infile.eof()){
break; // Not too nice but necessary because of last line problem
}
}
infile.close();
}
void cardealership::readOutputFileAndAlterInventory(){
std::ifstream infile;
std::string line;
infile.open(ordersFile.c_str(), std::ifstream::in);
if (!infile.good()){
std::cout << "Na na na Orders File" << "\n";
}
int id;
char* model;
int amountNeeded;
std::ofstream log("errorLog.txt");
if (!log.good()){
std::cout << "Na na na Log File" << "\n";
}
while (getline(infile, line)){
getline(infile, line);
std::stringstream helperStream;
helperStream << line;
helperStream >> id;
helperStream >> model;
helperStream >> amountNeeded;
if (mode == 0) { //Use linked list
linkedNode* tmpNode;
linkedNode* previousNode;
if (!linkedListOfCars.empty()){
tmpNode = linkedListOfCars.front();
while(tmpNode){
if (tmpNode->data == model) {
std::cout<< "Model found!" << std::endl;
}
if (tmpNode->amountOfCars > amountNeeded){
std::cout<< "Enough cars available!" << std::endl;
tmpNode->amountOfCars -= amountNeeded;
}
if (tmpNode->amountOfCars <= amountNeeded){ //
if (previousNode != NULL) {
linkedNode tmp3Node = *previousNode;
tmp3Node.next = tmpNode->next;
}
linkedNode* tmp2Node;
tmp2Node = tmpNode->next;
tmpNode = NULL;
tmpNode = tmp2Node;
//write error to log
log << "ID: "<< id << ", Not enough items!";
previousNode = tmpNode;
tmpNode = tmpNode->next;
}
}
if (!tmpNode) {
std::cout<< "Model not found." << std::endl;
//write error to log.
log << "ID: "<< id << ", Model not available!";
}
}
else{
std::cout<< "No cars to sell." << std::endl;
}
}
else if (mode == 1){ //Use STL list
if (!listOfCars.empty()) {
//Iterator copied and adapted from: http://www.cplusplus.com/reference/stl/list/begin/
std::list<linkedNode*>::iterator it;
for ( it=listOfCars.begin() ; it != listOfCars.end(); it++ ){
linkedNode* tmpNode = *it;
if (tmpNode->data == model) {
std::cout<< "Model found!" << std::endl;
}
if (tmpNode->amountOfCars >= amountNeeded){
std::cout<< "Enough cars available!" << std::endl;
tmpNode->amountOfCars -= amountNeeded;
}
if (tmpNode->amountOfCars < amountNeeded){
//delete entry and write error to log
it = listOfCars.erase(it);
log << "ID: "<< id << ", Not enough items!";
}
if (it++ == listOfCars.end()) {
//Write error to log if end of list is reached
log << "ID: "<< id << ", Model not available!";
}
}
}
else{
std::cout<< "No cars to sell." << std::endl;
}
}
else{
std::cout<< "Invalid mode." << std::endl;
}
}
infile.close();
}
void cardealership::printInventory (){
if (mode == 0) { //Use linked list
}
}
The post seems pretty long to me now but I hope I can still get some help...
Thanks in advance,
L

When adding a new linkedNode you declare a pointer to a node:
linkedNode* tmpNode;
The next mention of tmpNode is the following:
tmpNode->data = model;
However, tmpNode isn't a linkedNode, it's just a pointer to one. You're basically trying to save some data into space that other parts of your program may use. You need to make a linkedNode for tmpNode to point to so that it has its own storage. You may want to look into the new keyword.

Related

How to print data found in Binary Search Tree?

I am doing this program which reads a CSV file and enters it in a tree, until now I have managed to create the tree and it shows them in order, however with the search I have a failure since it does not show the information of the element that is being searched , someone who can help me correct the fault, thanks....
The csv file contains the data(contains several but I leave these for example.):
1,name1,number1
2,name2,number2
3,name3,number3
#include <iostream>
#include <iomanip>
#include <fstream>
#include <memory>
#include <string>
#include <sstream>
#include <vector>
#include <utility>
#include <experimental/optional>
intmax_t dato;
struct Person {
intmax_t key;
std::string name;
intmax_t num;
};
struct Node : Person {
Node(const Person &person) : Person(person) {}
std::unique_ptr<Node> left, right;
void insert(const Person &person);
};
void Node::insert(const Person &person) {
/* recur down the tree */
if (key > person.key) {
if (left)
left->insert(person);
else
left = std::make_unique<Node>(person);
} else if (key < person.key) {
if (right)
right->insert(person);
else
right = std::make_unique<Node>(person);
}
}
std::vector<Person> persons;
void inorder(Node *root) {
if (root) {
// cout<<"\t";
inorder(root->left.get());
std::cout << "\tID: "<< root->key << "\tName: "<< root->name << "\t\tNum: " << root->num << '\n'; //'\t' ' '
inorder(root->right.get());
}
}
std::experimental::optional<Person> busqueda(Node *root, intmax_t dato) {
if(root==NULL){
return {};
}
else if(root->key==dato){
return *root;
}
else if(dato<root->key){
return busqueda(root->left.get(),dato);
}
else{
return busqueda(root->right.get(),dato);
}
}
int main() {
std::unique_ptr<Node> root;
std::ifstream fin("data.txt");
if (!fin) {
std::cout << "File not open\n";
return 1;
}
std::string line;
const char delim = ',';
std::cout<<"\t\tData\n"<<std::endl;
while (std::getline(fin, line)) {
std::istringstream ss(line);
Person person;
ss >> person.key;
ss.ignore(10, delim);
std::getline(ss, person.name, delim);
ss >> person.num;
if (ss) persons.push_back(person);
}
for (unsigned int i = 0; i < persons.size(); i++) {
std::cout << std::setw(10)<<"ID: " << persons[i].key << std::setw(30)<<"Name: "
<< persons[i].name << std::setw(20) <<"Num: "<< persons[i].num << '\n';
if (!root) root = std::make_unique<Node>(persons[i]);
else root->insert(persons[i]);
}
std::cout << "\n\n\t\tInorder:\n\n";
inorder(root.get());
std::cout<<" Enter data: "; std::cin>> dato;
busqueda(root.get(),dato);
if(busqueda(root.get(),dato)){
std::cout<<"Data found"<<std::endl;
std::cout<<root->name;//does not show the wanted, only the first of the document.
}
else{
std::cout<<"\nData not found"<<std::endl;
}
return 0;
}
From the comments you throw away the result of your search in the following statement:
busqueda(root.get(),dato); returns an optional value std::experimental::optional but you don't make use of the value.
You test the value with if(busqueda(root.get(),dato)){ but since you did not store the result you both searched a second time and do not have a way to get the Person object.
Instead you can do this to get the person object and show its name:
std::cout << " Enter data: "; std::cin >> dato;
auto result = busqueda(root.get(), dato);
if (result) {
std::cout << "Data found" << std::endl;
std::cout <<result->name; // This should be the name of the found Person
}
else {
std::cout << "\nData not found" << std::endl;
}

How can I implement a linked list and allow users to choose a specific node to remove with C++?

I've spent pretty much all day trying to do this, I understand pointers and what a linked list does, but I don't know how to actually code it and all I've found are Java and C examples which don't help because I'm using C++.
Thanks in advance for taking a look at my code and helping me, I really appreciate it considering how many days I've spent stressed out and confused about this. I'm not going to lie so far most of my deleteNode function is probably trash. But like I've said I'm just lost I don't even know where to start or how to progress because I only understand the concepts.
This is my data file.
John Doe 80
Jane Smith 70
Bill Jones 50
Pat Hughes 90
Sam Sosa 40
This is my Header file
#include<string>
using namespace std;
class student {
public:
student(); // constructor method
void st_fn(string fn);
string st_fn();
void st_ln(string ln);
string st_ln();
void st_score(float s);
float st_score();
string st_pass_or_fail();
// need a pointer to the next object
student *nxt_ptr;
protected: // protected can be inherited
float m_score;
string m_ln;
string m_fn;
string m_pf_msg;
};
student::student() //constructor
{
nxt_ptr = NULL;
m_score = 0;
}
void student::st_fn(string fn)
{
m_fn = fn;
}
string student::st_fn()
{
return m_fn;
}
void student::st_ln(string ln)
{
m_ln = ln;
}
string student::st_ln()
{
return m_ln;
}
void student::st_score(float s)
{
m_score = s;
}
float student::st_score()
{
return m_score;
}
string student::st_pass_or_fail()
{
if (m_score >= 60)
m_pf_msg = "PASSED";
else
m_pf_msg = "FAILED";
return m_pf_msg;
}
This is my .cpp file.
#include<iostream>
#include<string>
#include<fstream>
#include "Header.h"
using namespace std;
int display_menu()
{
int option;
cout << endl << endl;
cout << "1. Display List" << endl;
cout << "2. Add a student" << endl;
cout << "3. Delete first student" << endl;
cout << "4. Search by Last Name" << endl;
cout << "5. Exit" << endl;
cin >> option;
return option;
}
student * search_last_name(student *h)
{
student *f = NULL;
student *t = NULL;
string s_ln;
// prompt for last name to search for
cout << "Enter Last Name of the Student";
cin >> s_ln;
if (h != NULL)
{
t = h;
while (t != NULL)
{
if (t->st_ln() == s_ln)
f = t; // found the last name so save t
t = t->nxt_ptr;
}
}
else
cout << "List is empty" << endl;
return f;
}
void add_student(student *&head) // h is the head of the list
{
student *new_st, *r;
string fn, ln;
float s;
cout << "Enter new students first name, last name and score";
cin >> fn >> ln >> s;
// instantiate a new node, use new_st
new_st = new student;
new_st->st_fn(fn);
new_st->st_ln(ln);
new_st->st_score(s);
if (head == NULL)
head = new_st;
else
{
// find the last node, use r for this
// write code
r = head;
while (r->nxt_ptr != nullptr)
r = r->nxt_ptr;
// add to the back of the list
// write code
r->nxt_ptr = new_st;
} // end of else
} // end of add student
student * delete_front(student * head)
{
student *t;
// delete front node
// check for empty list
if (head != NULL)
{
// delete first node
t = head;
head = head->nxt_ptr;
delete(t);
}
else
cout << "List is empty - nothing to delete" << endl;
return head;
}
void deleteNode(struct Node *head, struct Node *n)
{
// When node to be deleted is head node
if (head == n)
{
n = head->next;
//Remove the link of next node
head->next = head->next->next;
return;
}
//When not first node, folow the normal deletion process
//Find the previous node
struct Node *prev = head;
while (prev->next != NULL && prev->next != n)
prev = prev->next;
// Check if node really exists in Linked List
if (prev->next == NULL)
{
cout << endl << "Given node is not present in Linked List";
return;
}
//Remove node from linked list should it exist
prev->next = prev->next->next;
return;
}
void display_list(student *t)
{
if (t == NULL)
cout << "List is Empty!";
else
{
while (t != NULL)
{
cout << "******Student******" << endl;
cout << t->st_ln() << endl;
cout << t->st_fn() << endl;
cout << t->st_score() << endl << endl;
t = t->nxt_ptr;
}
}
}
int main()
{
string ln, fn;
float s;
int n;
ifstream infile;
student *head = NULL; //pointer to a student object
student *cp = NULL; // pointer to end of the list
student *new_st = NULL; // pointer to a new student object
student *f = NULL; // pointer to found node
int option; // the numbe of menu item the user selects
infile.open("lab8d.txt");
while (!infile.eof())
{
infile >> fn >> ln >> s;
//instantiate a student object
new_st = new student;
//load the object with data
new_st->st_fn(fn);
new_st->st_ln(ln);
new_st->st_score(s);
// check for empty list - its a special case
if (head == NULL)
{
head = new_st;
cp = new_st;
}
else // list is not empty
{
cp->nxt_ptr = new_st;
cp = new_st;
}
} // end of loop
// loop to give the user some options
option = display_menu();
while (option != 5)
{
if (option == 1)
display_list(head);
else if (option == 2)
add_student(head);
else if (option == 3)
head = delete_front(head);
else if (option == 4)
{
f = search_last_name(head);
if (f != NULL)
{
cout << f->st_fn() << endl;
cout << f->st_ln() << endl;
cout << f->st_score() << endl;
cout << f->st_pass_or_fail() << endl;
}
else
cout << "Name not in the list" << endl;
}
else if (option == 6)
{
cout << "Enter the number of the node you would like to delete: " << endl;
cin >> n;
}
option = display_menu();
}
system("pause");
return 0;
}
The simpler and self-contained your functions are, the easier they are to test and debug, and the less like they are to fail.
Try something more like this:
Student.h:
#include <string>
class student_list;
class student
{
public:
student();
student(const std::string &fn, const std::string &ln, float s, student *nxt = NULL);
void next(student *s);
student* next() const;
void firstName(const std::string &fn);
std::string firstName() const;
void lastName(const std::string &ln);
std::string lastName() const;
void score(float s);
float score() const;
std::string pass_or_fail() const;
void display(bool showPassOrFail = false) const;
friend class student_list;
protected: // protected can be inherited
student *m_next;
std::string m_fn;
std::string m_ln;
float m_score;
};
Student.cpp:
#include "Student.h"
#include <iostream>
student::student()
: m_next(NULL), m_score(0)
{
}
student::student(const std::string &fn, const std::string &ln, float s, student *nxt)
: m_next(nxt), m_fn(fn), m_ln(ln), m_score(s)
{
}
void student::next(student *s)
{
m_next = s;
}
student* student::next() const
{
return m_next;
}
void student::firstName(const std::string &fn)
{
m_fn = fn;
}
std::string student::firstName() const
{
return m_fn;
}
void student::lastName(const std::string &ln)
{
m_ln = ln;
}
std::string student::lastName() const
{
return m_ln;
}
void student::score(float s)
{
m_score = s;
}
float student::score() const
{
return m_score;
}
std::string student::pass_or_fail() const
{
if (m_score >= 60)
return "PASSED";
else
return "FAILED";
}
void student::display(bool showPassOrFail) const
{
std::cout << lastName() << std::endl;
std::cout << firstName() << std::endl;
std::cout << score() << std::endl;
if (showPassOrFail)
std::cout << pass_or_fail() << std::endl;
}
StudentList.h:
#include <string>
class student;
class student_list
{
public:
student_list();
~student_list();
student* search_last_name(const std::string &ln);
student* insert(const std::string &fn, const std::string &ln, float s, student* after = NULL);
bool remove(int idx);
void display() const;
private:
student *m_head;
};
StudentList.cpp:
student_list::student_list()
: m_head(NULL)
{
}
student_list::~student_list()
{
while (m_head)
remove(0);
}
student* student_list::search_last_name(const std::string &ln)
{
student *t = m_head;
while (t)
{
if (t->lastName() == ln)
break; // found the last name
t = t->next();
}
return t;
}
student* student_list::insert(const std::string &fn, const std::string &ln, float s, student* after)
{
student **r;
if (after)
{
// add to list after the specified node
// get pointer to next node
r = &(after->m_next);
}
else
{
// add to the back of the list
// find pointer to last node
r = &m_head;
while (*r)
r = &((*r)->m_next);
}
// instantiate a new node
student *new_st = new student(fn, ln, s);
if (after)
new_st->next(*r);
// add to list
*r = new_st;
return new_st;
}
bool student_list::remove(int idx)
{
// delete a node at index
// find pointer to node
student **r = &m_head;
while ((*r) && (idx-- > 0))
r = &((*r)->m_next);
if (*r)
{
// delete node
student *t = *r;
*r = t->next();
delete t;
return true;
}
return false;
}
void student_list::display() const
{
student *t = m_head;
if (!t)
std::cout << "List is Empty!" << std::endl;
else
{
do
{
std::cout << "******Student******" << std::endl;
t->display();
t = t->next();
}
while (t);
}
}
Main.cpp:
#include "Student.h"
#include "StudentList.h"
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <limits>
#include <cstdlib>
int read_number()
{
int value;
while (!(std::cin >> value))
{
std::cout << "Must be a number, try again: ";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
return value;
}
int display_menu()
{
int option;
std::cout << std::endl << std::endl;
std::cout << "1. Display List" << std::endl;
std::cout << "2. Add a student" << std::endl;
std::cout << "3. Delete first student" << std::endl;
std::cout << "4. Search by Last Name" << std::endl;
std::cout << "5. Delete student by index" << std::endl;
std::cout << "6. Exit" << std::endl << std::endl;
std::cout << "Choice: ";
do
{
option = read_number();
if ((option >= 1) && (option <= 6))
break;
std::cout << "Must be 1..6, try again: ";
}
while (true);
return (option != 6) ? option : -1;
}
int main()
{
student_list students;
std::ifstream infile("lab8d.txt");
if (infile.is_open())
{
student *cp = NULL;
std::string ln, fn;
float s;
while (infile >> fn >> ln >> s)
cp = students.insert(fn, ln, s, cp);
infile.close();
}
// loop to give the user some options
int option; // the number of menu item the user selects
while ((option = display_menu()) != -1)
{
switch (option)
{
case 1:
{
students.display();
break;
}
case 2:
{
// prompt for student info
std::string info;
std::cout << "Enter new student's first name, last name, and score: ";
std::string ln, fn;
float s;
if (std::cin >> fn >> ln >> s)
students.insert(fn, ln, s);
break;
}
case 3:
{
if (!students.remove(0))
std::cout << "List is empty" << std::endl;
break;
}
case 4:
{
// prompt for last name to search for
std::string ln;
std::cout << "Enter Last Name of the Student: ";
if (std::cin >> ln)
{
student *f = students.search_last_name(ln);
if (f)
f->display(true);
else
std::cout << "Name not found in List" << std::endl;
}
break;
}
case 5:
{
std::cout << "Enter the index of the Student to Delete: " << std::endl;
int idx = read_number();
if (!students.remove(idx))
std::cout << "Index not found in List" << std::endl;
break;
}
}
}
std::system("pause");
return 0;
}
That being said, you really should be using the std::list container instead, eg:
Student.h:
#include <string>
class student_list;
class student
{
public:
student();
student(const std::string &fn, const std::string &ln, float s);
void firstName(const std::string &fn);
std::string firstName() const;
void lastName(const std::string &ln);
std::string lastName() const;
void score(float s);
float score() const;
std::string pass_or_fail() const;
void display(bool showPassOrFail = false) const;
friend class student_list;
protected: // protected can be inherited
std::string m_fn;
std::string m_ln;
float m_score;
};
Student.cpp:
#include "Student.h"
#include <iostream>
student::student()
: m_score(0)
{
}
student::student(const std::string &fn, const std::string &ln, float s)
: m_fn(fn), m_ln(ln), m_score(s)
{
}
void student::firstName(const std::string &fn)
{
m_fn = fn;
}
std::string student::firstName() const
{
return m_fn;
}
void student::lastName(const std::string &ln)
{
m_ln = ln;
}
std::string student::lastName() const
{
return m_ln;
}
void student::score(float s)
{
m_score = s;
}
float student::score() const
{
return m_score;
}
std::string student::pass_or_fail() const
{
if (m_score >= 60)
return "PASSED";
else
return "FAILED";
}
void student::display(bool showPassOrFail) const
{
std::cout << lastName() << std::endl;
std::cout << firstName() << std::endl;
std::cout << score() << std::endl;
if (showPassOrFail)
std::cout << pass_or_fail() << std::endl;
}
Main.cpp:
#include "Student.h"
#include <list>
#include <iostream>
#include <string>
#include <fstream>
#include <sstream>
#include <limits>
#include <algorithm>
#include <cstdlib>
int read_number()
{
int value;
while (!(std::cin >> value))
{
std::cout << "Must be a number, try again: ";
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
return value;
}
int display_menu()
{
int option;
std::cout << std::endl << std::endl;
std::cout << "1. Display List" << std::endl;
std::cout << "2. Add a student" << std::endl;
std::cout << "3. Delete first student" << std::endl;
std::cout << "4. Search by Last Name" << std::endl;
std::cout << "5. Delete student by index" << std::endl;
std::cout << "6. Exit" << std::endl << std::endl;
std::cout << "Choice: ";
do
{
option = read_number();
if ((option >= 1) && (option <= 6))
break;
std::cout << "Must be 1..6, try again: ";
}
while (true);
return (option != 6) ? option : -1;
}
int main()
{
std::list<student> students;
std::ifstream infile("lab8d.txt");
if (infile.is_open())
{
std::string ln, fn;
float s;
while (infile >> fn >> ln >> s)
students.push_back(student(fn, ln, s));
infile.close();
}
// loop to give the user some options
int option; // the number of menu item the user selects
while ((option = display_menu()) != -1)
{
switch (option)
{
case 1:
{
if (students.empty())
std::cout << "List is Empty!" << std::endl;
else
{
for(const auto &s : students)
{
std::cout << "******Student******" << std::endl;
s.display();
}
}
break;
}
case 2:
{
// prompt for student info
std::string info;
std::cout << "Enter new student's first name, last name, and score: ";
std::string ln, fn;
float s;
if (std::cin >> fn >> ln >> s)
students.push_back(student(fn, ln, s));
break;
}
case 3:
{
if (students.empty())
std::cout << "List is empty" << std::endl;
else
students.erase(students.begin());
break;
}
case 4:
{
// prompt for last name to search for
std::string ln;
std::cout << "Enter Last Name of the Student: ";
if (std::cin >> ln)
{
auto f = std::find(students.begin(), students.end(),
[&](const student &s){ return (s.lastName() == ln); }
);
if (f != students.end())
f->display(true);
else
std::cout << "Name not found in List" << std::endl;
}
break;
}
case 5:
{
std::cout << "Enter the index of the Student to Delete: " << std::endl;
int idx = read_number();
if ((idx < 0) || (idx >= students.size()))
std::cout << "Index not found in List" << std::endl;
else
students.erase(std::next(students.begin(), idx));
break;
}
}
}
std::system("pause");
return 0;
}

Segmentation Fault 11 on return

I realize there are other answers like this one but seg faults are pretty general and none of them fit my situation exactly. I am creating a binary tree and storing data. In the printInOrder function, it recurses all the way to the furthest leftChild and then seg faults when it reaches the return statement. I am not sure why it is doing this. Thanks in advance for the help.
#include <string>
#include <cstdlib>
#include <iostream>
#include "BST.h"
using namespace std;
BST::BST(void) {
root = NULL;
cout << "Default object is being creating." << "\n";
};
/*
BST::BST(string word, int count) {
cout << "Default object is being creating." << "\n";
this->root->word = word;
this->root->count = count;
};
BST::BST(string word) {
cout << "Default object is being creating." << "\n";
this->root->word = word;
this->root->count = 1;
};
*/
bool BST::hasWord(string word) {
return true;
};
void BST::printInOrder() {
pio(this->root);
}
void BST::pio(struct node* node) {
cout << "root: " << root << endl;
cout << "node: " << node << endl;
cout << "leftChild: " << node->leftChild->leftChild << endl;
if (node != NULL){
/* first recur on left child */
pio(node->leftChild);
/* then print the data of node */
cout << "Word: " << node->word << endl;
cout << "Count: " << node->count << endl;
/* now recur on right child */
pio(node->rightChild);
}
if (node == NULL) {
return;
}
}
void BST::insert(string word)
{
if(this->root != NULL)
insert(word, this->root);
else
{
cout << "obj has been inserted " << endl;
this->root = new node;
cout << root << endl;
this->root->word = word;
this->root->count = 1;
this->root->leftChild = NULL;
this->root->rightChild = NULL;
}
}
void BST::insert(string word, struct node *leaf)
{
if(word< leaf->word)
{
if(leaf->leftChild != NULL)
insert(word, leaf->leftChild);
else
{
cout << "obj has been inserted " << endl;
leaf->leftChild = new node;
cout << leaf->leftChild << endl;
leaf->leftChild->word = word;
leaf->leftChild->count = 1;
leaf->leftChild->leftChild = NULL; //Sets the leftChild child of the child node to null
leaf->leftChild->rightChild = NULL; //Sets the rightChild child of the child node to null
}
}
else if(word>leaf->word)
{
if(leaf->rightChild != NULL)
insert(word, leaf->rightChild);
else
{
cout << "obj has been inserted " << endl;
leaf->rightChild = new node;
cout << leaf->rightChild << endl;
leaf->rightChild->word = word;
leaf->rightChild->count = 1;
leaf->rightChild->leftChild = NULL; //Sets the leftChild child of the child node to null
leaf->rightChild->rightChild = NULL; //Sets the rightChild child of the child node to null
}
}
//word is already in the tree so we increment counter
else leaf->count += 1;
}
Main file:
#include <string>
#include <vector>
#include <fstream>
#include <iostream>
#include <dirent.h>
#include <cstring>
#include <functional>
#include <algorithm>
#include <sstream>
#include "BST.h"
using namespace std;
void parseFile(string fullPath, BST bst) {
ifstream infile(fullPath); // Open it up!
std::string line;
char c;
string word = "";
while (std::getline(infile, line))
{
// Iterate through the string one letter at a time.
for (int i = 0; i < line.length(); i++) {
c = line.at(i); // Get a char from string
tolower(c);
// if it's NOT within these bounds, then it's not a character
if (! ( ( c >= 'a' && c <= 'z' ) || ( c >= 'A' && c <= 'Z' ) ) ) {
//if word is NOT an empty string, insert word into bst
if ( word != "" ) {
bst.insert(word);
//reset word string
word = "";
}
}
else {
word += string(1, c);
}
}
}
}
void getReqDirs(BST bst, const string path, vector<string> files,const bool showHiddenDirs = false){
DIR *dpdf;
struct dirent *epdf;
dpdf = opendir(path.c_str());
int count = 0;
if (dpdf != NULL){
while ((epdf = readdir(dpdf)) != NULL){
if(showHiddenDirs ? (epdf->d_type==DT_DIR && string(epdf->d_name) != ".." && string(epdf->d_name) != "." ) : (epdf->d_type==DT_DIR && strstr(epdf->d_name,"..") == NULL && strstr(epdf->d_name,".") == NULL ) ){
getReqDirs(bst,path+epdf->d_name+"/",files, showHiddenDirs);
}
if(epdf->d_type==DT_REG){
//files.push_back(path+epdf->d_name);
//parseFile(path+epdf->d_name, bst);
cout << path+epdf->d_name << " ";
}
}
}
closedir(dpdf);
}
int main()
{
vector <string> words; // Vector to hold our words we read in.
string str; // Temp string to
cout << "Read from a file!" << endl;
BST bst;
string path = "test/"; //name of directory that holds the data base
vector<string> files; //create vector for file names
/*
//collect all the file names in the data base
getReqDirs(bst,path,files,false);
for (int i = 0; i < files.size(); i++) {
cout << files[i] << " ";
}*/
bst.insert("gary");
bst.insert("Mil");
bst.insert("Taylor");
bst.insert("BrIaN");
bst.insert("fart");
bst.insert("Juan");
bst.insert("James");
bst.insert("Gary");
bst.printInOrder();
//parseFile(path, bst);
return 0;
}
Please let me know if any other info is required.
The following line is the only problematic line of code I found in pio:
cout << "leftChild: " << node->leftChild->leftChild << endl;
It is a problem since node is bound be NULL at some point.
Remove that line.
Also, you don't need the lines
if (node == NULL) {
return;
}
They don't do anything useful and can be removed. Here's an updated version of the function:
void BST::pio(struct node* node) {
cout << "root: " << root << endl;
cout << "node: " << node << endl;
if (node != NULL){
/* first recur on left child */
pio(node->leftChild);
/* then print the data of node */
cout << "Word: " << node->word << endl;
cout << "Count: " << node->count << endl;
/* now recur on right child */
pio(node->rightChild);
}
}

Using a print function to output to a new file

I have a program analyzing the number of distinct and total words in a text file and then writing it to a new output file. I've got the first part down, but I don't know how to get my print function to print onto the new text file. Printing the total words or distinct words onto the new file works but the Print2() function doesn't seem to work. Please take a look at the //POINT OF INTEREST// section, where i believe the problem stems.
#include <iostream>
#include <fstream>
#include <string>
#include <cctype>
int distinctWord = 0;
using namespace std;
typedef int ItemType;
struct Node {
string word;
int count = 1;
Node* left;
Node* right;
};
class TreeType {
private:
Node* root;
void Insert(Node*& root, string word);
void Destroy(Node*& root);
void PrintTree(Node* root);
void Print2File(Node* root, ofstream& fout);
public:
TreeType() {root = nullptr;}
~TreeType();
void PutItem(string word);
void Print();
void Print2(ofstream& fout);
};
void TreeType::Print() {
PrintTree(root);
cout << endl;
}
void TreeType::PrintTree(Node* root) {
if (root == nullptr)
return;
PrintTree(root->left);
cout << root->word << " " << root->count << endl;
PrintTree(root->right);
}
///////////////POINT OF INTEREST///////////////////////////
///////////////POINT OF INTEREST///////////////////////////
void TreeType::Print2File(Node* root, ofstream& fout){
if (root == nullptr)
return;
PrintTree(root->left);
fout << root->word << " " << root->count << endl;
PrintTree(root->right);
}
void TreeType::Print2(ofstream& fout) {
Print2File(root, fout);
cout << "Printed to another file" << endl;
}
///////////////POINT OF INTEREST///////////////////////////
///////////////POINT OF INTEREST///////////////////////////
void TreeType::PutItem(string word) {
Insert(root, word);
}
void TreeType::Insert(Node*& root, string word) {
if (root == nullptr) {
root = new Node;
distinctWord++;
root->word = word;
root->right = nullptr;
root->left = nullptr;
return;
}
if(root->word == word){
root->count++;
return;
}else if (word < root->word)
Insert(root->left, word);
else
Insert(root->right, word);
}
TreeType::~TreeType() {
Destroy(root);
}
int main(int argc, const char * argv[]) {
int totalwords = 0;
ifstream file;
string word;
char c;
ofstream fout;
ifstream file;
string filename;
cout << "Enter name of file with text to analyze: ";
cin >> filename;
fin.open(filename.c_str());
if (fin.fail()) {
cout << "Error opening file.\n";
exit(1);
}
cout << "\nAnalyzing " << filename << ".\n";
TreeType t;
while(!file.eof()){
file.get(c);
if(isalpha(c) || c == '\''){
word += c;
c = '\0';
}else if(c == ' ' || c == '\n' || c == '-' || c == '.'){
if(isalpha(word[0])){
transform(word.begin(), word.end(), word.begin(), ::tolower);
t.PutItem(word);
totalwords++;
word = "";
c = '\0';
}
}
}if(isalpha(word[0])){
transform(word.begin(), word.end(), word.begin(), ::tolower);
t.PutItem(word);
totalwords++;
}
file.close();
fout.open("results.txt");
cout << "\nWord counts:\n\n";
t.Print();
t.Print2(fout);
cout << "\nTotal number of words in text: " << totalwords << ".\n";
fout << "\nTotal number of words in text: " << totalwords << ".\n";
cout << "Number of distinct words appearing in text: "
<< distinctWord << ".\n";
fout << "Number of distinct words appearing in text: "
<< distinctWord << ".\n";
fout.close();
return 0;
}
You will have to pass your output file stream to your
PrintTree(root); too.
Right now you are printing to cout which will dump everything to whatever console your application is associated with.
The modified function after adding the ofstream parameter becomes:
void TreeType::PrintTree(Node* root, ofstream &fout) {
if (root == nullptr)
return;
PrintTree(root->left, fout);
fout << root->word << " " << root->count << endl;
PrintTree(root->right, fout);
}
You will need to pass the ofstream object throughout in all callers of PrintTree

Why is this string changed?

I have the following code, so far, I want to check if a file name is already in the linked list fileList (or flist). according to the output, the string saved in the first Node was changed somewhere in Node* getFileName(Node *&flist) How did this happen? Also, is there anything else that I'm doing is wrong or not safe regarding pointers of Node and strings?
output:
in main: file4.txt
start of process: file4.txt
file4.txt
mid of process: file4.txt"
in contains, fileName in node: file4.txt"
in contains, target file name: file4.txt
end of process: file4.txt"
0
no recursive call
code:
struct Node {
string fileName;
Node *link;
};
/*
*
*/
bool contains (Node *&flist, string &name) {
Node *tempNode = *&flist;
while (tempNode != 0) {
cout << "in contains, fileName in node: " << flist->fileName << endl;
cout << "in contains, target file name: " << name << endl;
if ((tempNode->fileName) == name) {
return true;
}
else {
tempNode = tempNode->link;
}
}
return false;
}
/*
*
*/
Node* getLastNode (Node *&flist) {
Node *tempNode = *&flist;
while (tempNode != 0) {
tempNode = tempNode->link;
}
return tempNode;
}
/*
*
*/
string getFileName(string oneLine) {
char doubleQuote;
doubleQuote = oneLine[9];
if (doubleQuote == '\"') {
string sub = oneLine.substr(10); //getting the file name
string::size_type n = sub.size();
sub = sub.substr(0,n-1);
cout << sub << endl;
return sub;
}
return NULL;
}
/*
*
*/
void process( istream &in, ostream &out, Node *&flist ) {
cout << "start of process: " << flist->fileName << endl;
string oneLine; //temp line holder
while (getline(in, oneLine)) {
// cout << oneLine << endl;
string::size_type loc = oneLine.find("#include",0);
if (loc != string::npos) {
//found one line starting with "#include"
string name;
name = getFileName(oneLine);
cout << "mid of process: " << flist->fileName << endl;
bool recursive;
recursive = contains(flist, name);
cout << "end of process: " << flist->fileName << endl;
cout << recursive << endl;
if (recursive) {
//contains recursive include
cerr << "recursive include of file " << name << endl;
exit(-1);
}
else {
//valid include
cout << "no recursive call" << endl;
}//else
}//if
}//while
}//process
/*
*
*/
int main( int argc, char *argv[] ) {
istream *infile = &cin; // default value
ostream *outfile = &cout; // default value
Node* fileList;
switch ( argc ) {
case 3:
outfile = new ofstream( argv[2] ); // open the outfile file
if ( outfile->fail() ) {
cerr << "Can't open output file " << argv[2] << endl;
exit( -1 );
}
// FALL THROUGH to handle input file
case 2:
infile = new ifstream( argv[1] ); // open the input file
if ( infile->fail() ) {
cerr << "Can't open input file " << argv[1] << endl;
exit( -1 );
}
else {
Node aFile = {argv[1], 0};
fileList = &aFile;
cout << "in main: " << fileList->fileName << endl;
}
// FALL THROUGH
case 1: // use cin and cout
break;
default: // too many arguments
cerr << "Usage: " << argv[0] << " [ input-file [ output-file ] ]" << endl;
exit( -1 ); // TERMINATE!
}
processOneFile (*infile, *outfile, fileList);
// do something
if ( infile != &cin ) delete infile; // close file, do not delete cin!
if ( outfile != &cout ) delete outfile; // close file, do not delete cout!
}
Could you post the original code? The code you posted doesn't even compile.
Errors I've noticed, in order:
processOneFile (*infile, *outfile, fileList);
There is no processOneFile() procedure.
istream *infile = &cin; // default value
ostream *outfile = &cout; // default value
Node* fileList;
case 1: // use cin and cout
break;
processOneFile (*infile, *outfile, fileList);
This will call processOneFile() with an uninitialized file list, which will crash when you try to print the file name.
else {
Node aFile = {argv[1], 0};
fileList = &aFile;
cout << "in main: " << fileList->fileName << endl;
}
aFile is only in scope within that else, so trying to use a pointer to it later will fail.
string getFileName(string oneLine) {
///
return NULL;
}
You can't construct a std::string from NULL -- this will crash the program.
After fixing these errors so your code wouldn't crash, I couldn't reproduce the error.
If you're building in Linux, try increasing the warning level (with g++ -Wall -Wextra -ansi -pedantic) and running your code through valgrind, to check for memory errors.
Ok, the code does now seem like it works as expected:
#include <iostream>
#include <fstream>
using namespace::std;
struct Node
{
string fileName;
Node *link;
};
bool contains (Node *&flist, string &name)
{
Node *tempNode = *&flist;
while (tempNode != 0)
{
cout << "Searching in \"" << flist->fileName;
cout << "\" for \"" << name << "\"" << endl;
if ( tempNode->fileName == name)
{
return true;
}
else
{
tempNode = tempNode->link;
}
}
return false;
}
Node* getLastNode (Node *&flist)
{
Node *tempNode = *&flist;
while (tempNode != 0)
{
tempNode = tempNode->link;
}
return tempNode;
}
string getFileName(string oneLine)
{
char doubleQuote;
doubleQuote = oneLine[9];
if (doubleQuote == '\"') {
string sub = oneLine.substr(10); //getting the file name
string::size_type n = sub.size();
sub = sub.substr(0,n-1);
return sub;
}
return "";
}
void process( istream &in, ostream &out, Node *&flist )
{
cout << "Start of process: " << flist->fileName << endl << endl;
string oneLine;
while (1)
{
cout << "Input include statement: ";
getline(in, oneLine);
if (oneLine == "STOP")
return;
string::size_type loc = oneLine.find("#include",0);
if (loc != string::npos)
{
//found one line starting with "#include"
string name;
name = getFileName(oneLine);
if (name == "")
{
cout << "Couldn't find filename, skipping line..." << endl;
continue;
}
if (contains(flist, name))
{
//contains recursive include
cerr << "Uh, oh! Recursive include of file " << name << endl;
exit(-1);
}
else
{
cerr << "No recursive include" << endl;
}
}//if
cout << endl;
}//while
}
int main( int argc, char *argv[] )
{
Node* fileList = new Node;
istream *infile = &cin; // default value
ostream *outfile = &cout; // default value
fileList->fileName = "Input"; // default value
switch ( argc )
{
case 3:
outfile = new ofstream( argv[2] ); // open the outfile file
if ( outfile->fail() ) {
cerr << "Can't open output file " << argv[2] << endl;
exit( -1 );
}
// FALL THROUGH to handle input file
case 2:
infile = new ifstream( argv[1] ); // open the input file
if ( infile->fail() ) {
cerr << "Can't open input file " << argv[1] << endl;
exit( -1 );
}
else {
fileList->fileName = argv[1];
cout << "in main: " << fileList->fileName << endl;
}
// FALL THROUGH
case 1: // use cin and cout
break;
default: // too many arguments
cerr << "Usage: " << argv[0] << " [ input-file [ output-file ] ]" << endl;
exit( -1 ); // TERMINATE!
}
process(*infile, *outfile, fileList);
// do something
if ( infile != &cin ) delete infile; // close file, do not delete cin!
if ( outfile != &cout ) delete outfile; // close file, do not delete cout!
}
Also, why are you wasting time writing your own linked list when the standard library already has a perfectly good one?