I am trying to print my vector in the display function, but it fails. I'm about 80% sure my syntax is correct. I have tried passing it from class to class. I am sure the file is being read in correctly because when I put my for loop in ClientProcessing() it works fine but I want to separate them.
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
// struct to hold the initial information of each client
struct Clients
{
string client_name = " "; // first and last as one line
char account_type = ' '; // C for Checking - S for savings;
double initial_deposit = 0.0; // Amount for initial deposit
};
// Prototype for Account Manager
class AccManager
{
public:
vector<Clients> client_info;
string client_name = ""; // first and last as one line
char account_type = ' '; // C for Checking / S for savings;
double initial_deposit = 0.0; // Amount for initial deposit
AccManager(){};
void set_name(string n) {client_name = n;};
string get_name(){return client_name;};
void set_type(char t){account_type = t;};
char get_type(){return account_type;};
void set_initial_deposit(double d){initial_deposit = d;};
double get_initial_deposit(){return initial_deposit;};
};
// Prototype for the UI - User interface
class UI
{
public:
void ClientProcessing();
void ShowClientInfo();
};
int main()
{
UI ui;
ui.ClientProcessing();
ui.ShowClientInfo();
}
// A module that reads in the the client data file
void UI::ClientProcessing()
{
ifstream infile;
AccManager a;
int i = 0;
cout << "Processing client information...\n";
infile.open("client_data.txt");
if(infile.is_open()){
cout << "Opened client file sucessfully! \n";
while(!infile.eof()){
while (i < 1){
getline(infile, a.client_name, '\t');
a.set_name(a.client_name);
a.client_info.push_back(Clients());
a.client_info[i].client_name = a.get_name();
i++;
}
}
}
else{
cout << "Error opening file! \n";
}
infile.close();
}
// A module to display the client info as a table
void UI::ShowClientInfo()
{
AccManager a;
cout << "Name D\n";
for(int i = 0; i < a.client_info.size(); i++){
cout << a.client_info[i].client_name; // Will not print here
}
}
Converted my code to the following and passed in the vector. It worked!
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
// struct to hold the initial information of each client
struct Clients
{
string client_name = " "; // first and last as one line
char account_type = ' '; // C for Checking - S for savings;
double initial_deposit = 0.0; // Amount for initial deposit
};
// Prototype for Account Manager
class AccManager
{
public:
vector<Clients> client_info;
string client_name = ""; // first and last as one line
char account_type = ' '; // C for Checking / S for savings;
double initial_deposit = 0.0; // Amount for initial deposit
AccManager(){};
void set_name(string n) {client_name = n;};
string get_name(){return client_name;};
void set_type(char t){account_type = t;};
char get_type(){return account_type;};
void set_initial_deposit(double d){initial_deposit = d;};
double get_initial_deposit(){return initial_deposit;};
};
// Prototype for the UI - User interface
class UI
{
public:
void ClientProcessing(vector<Clients> &client_info);
void ShowClientInfo(vector<Clients> client_info);
};
int main()
{
UI ui;
AccManager a;
ui.ClientProcessing(a.client_info);
ui.ShowClientInfo(a.client_info);
}
// A module that reads in the the client data file
void UI::ClientProcessing(vector<Clients> &client_info)
{ AccManager a;
ifstream infile;
int i = 0;
cout << "Processing client information...\n";
infile.open("client_data.txt");
if(infile.is_open()){
cout << "Opened client file sucessfully! \n";
while(!infile.eof()){
while (i < 1){
getline(infile, a.client_name, '\t');
a.set_name(a.client_name);
client_info.push_back(Clients());
client_info[i].client_name = a.get_name();
i++;
}
}
}
else{
cout << "Error opening file! \n";
}
infile.close();
}
// A module to display the client info as a table
void UI::ShowClientInfo(vector<Clients> client_info)
{
cout << "Name D\n";
for(int i = 0; i < client_info.size(); i++){
cout << client_info[i].client_name;
}
}
I need to make a program that will ask the user for his name and id as 1 string, and after provide a separate name and id. For example:
Enter the student info: Kobe Bean Bryant 51012345.
Student name is: Kobe Bean Bryant
Student ID is: 51012345
I tried it by myself, getting a different output, such as:
Student name is: Kobe Bean Bryant
Student ID is:&#
Here is my code:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int getNameAndID(char nameid[]) {
char name[50];
char id[50];
bool notnumber=true;
int i=0;
for (i; nameid[i]!='\0'; i++) {
if (nameid[i] >= '0' && nameid[i] <= '9') {
notnumber = false;
}
if (notnumber) {
name[i] = nameid[i];
}
else if (!notnumber) {
id[i] = nameid[i];
}
}
cout << "Student name is: " << name;
cout << "\nStudent ID is: " << id;
}
int main() {
cout << "Enter the student information: ";
char a[50];
cin.getline(a, 50);
getNameAndID(a);
}
Still some problem with ID.
Can't understand what is wrong, please help me:(
(Edited by setting bool and int to true and 0 respectively)
Couple of things I spotted in your code:
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
int getNameAndID(char nameid[]) {
char name[50];
char id[50];
bool notnumber;
int i;
for (i; nameid[i]!='\0'; i++) { // <---- (1)
if (nameid[i] >= 48 && nameid[i] <= 57) {
notnumber = false;
}
if (notnumber) { // <---- (2)
name[i] = nameid[i];
}
else if (!notnumber) {
id[i] = nameid[i];
}
}
cout << "Student name is: " << name;
cout << "\nStudent ID is: " << id;
// <---- (3)
}
int main() {
cout << "Enter the student information: ";
char a[50];
cin.getline(a, 50);
getNameAndID(a);
}
(1) i is never initialized, which invokes undefined behavior by accessing nameid[i].
(2) name[i] = nameid[i]; This does not append nameid[i] on name[i], (same applies for id[i] = nameid[i];). Consider the following:
index: 0 1 2 3 4 5 6 7 8 9
nameid: hello world 1 2 3 4
id: ? ? ? ? ? ? 1 2 3 4
There will be a portion of uninitialized values at the beginning of id. keeping a separate index for id for assignment should do what you want.
(3) No value is returned in int getNameAndID(), which also invokes undefined behavior.
Since you're using C++ not C, You'll make your life a lot easier by using std::string, you might want to do something similar to this:
void getNameAndID(string info) {
string name, id;
bool noDigit = true;
for (auto c : info) {
noDigit &= !isdigit(c);
if (noDigit)
name += c;
else id += c;
}
cout << "Student name is: " << name << '\n';
cout << "Student ID is: " << id;
}
int main() {
cout << "Enter the student information: ";
string info;
getline(cin, info);
getNameAndID(info);
return 0;
}
You need to keep different indices for name and id, in addition to the index used to traverse the input array nameid.
Increment each char array's index after inserting a character and at the end remember to add null terminators.
i needs to be initialized to zero.
i have been provided middleearth.h/cpp and was asked to make a makefile, doxyfile (which i did correctly) and a topological.cpp that works but has a small mistake in the output and i need help with that please.ill provide all three files and the text we use to test and the error.
cs2110 cs2150
cs2102 cs2150
cs1110 cs2110
cs3330 cs4414
cs2150 cs4414
cs2110 cs3330
cs1110 cs2102
0 0
middleearth.h
#ifndef MIDDLEEARTH_H
#define MIDDLEEARTH_H
#include <iostream>
#include <vector>
#include <string>
#include <unordered_map>
#include <random>
using namespace std;
// see the comments in the lab11 write-up, or in middleearth.cpp
class MiddleEarth {
public:
MiddleEarth(int xsize, int ysize, int num_cities, int seed);
void print();
void printTable();
float getDistance(const string& city1, const string& city2);
vector<string> getItinerary(unsigned int length);
private:
int num_city_names, xsize, ysize;
unordered_map<string, float> xpos, ypos;
vector<string> cities;
unordered_map<string, unordered_map<string, float>> distances;
mt19937 gen; // Mersenne-Twister random number engine
};
#endif
middleearth.cpp
#include "middleearth.h"
#include <algorithm>
#include <array>
#include <cstdlib>
#include <cmath>
// New shuffle method that uses the Mersenne Twister engine
void shuffle (vector<string>::iterator first, vector<string>::iterator last, mt19937& g) {
for (auto i=(last-first)-1; i>0; --i) {
unsigned int n = (g() / (double) g.max())*distance(first,last);
swap (first[i], first[n]);
}
}
// The list of all the place names that we'll be using
const array<string, 40> all_city_names{
// human towns, cities and strongholds
"Bree", // a human and hobbit town between the Shire and Rivendell
"Isengard", // the tower fortress where Saruman resided; Gandalf was imprisoned there.
"Minas Tirith", // capital of Gondor, the "white city"; home to Boromir, Denethor, and later, Aragorn
"Osgiliath", // city on the river Anduin; is at the other end of Pelennor Fields from M. Tirith
"Edoras", // the capital city of Rohan, where King Theoden resides
"Helm's Deep", // fortress of Rohan, it is where the people of Edoras fled to from the orc invasion
"Dunharrow", // a refuge of Rohan, it is where Elrond presents the sword to Aragorn in the movie
// dwarf cities
"Moria", // the enormous dwarven underground complex that the Fellowship traveled through
// elvish cities
"Lothlorien", // the elvish tree-city, home of Lady Galadriel and Lord Celeborn
"Rivendell", // the elvish city that is home to Lord Elrond
"The Grey Havens", // the port city on the western coast from which the elves travel westward
// hobbit villages
"Bucklebury", // a Shire village, it has a ferry across the Brandywine River that the Hobbits use
"Bywater", // a Shire village, it is the site of the Battle of Bywater (removed from the movie)
"Hobbiton", // a Shire village, it is home to Bilbo and, later, Frodo
"Michel Delving", // a Shire village, it is the chief town of the Shire
// Mordor places
"Orodruin", // Mount Doom in Mordor, it is where the Ring was made, and later, unmade
"Barad-Dur", // Sauron's fortress that was part castle, part mountain
"Minas Morgul", // formerly the Gondorian city of Minas Ithil; renamed when Sauron took it over
"Cirith Ungol", // the mountianous pass that Sam & Frodo went through; home of Shelob
"Gorgoroth", // the plains in Mordor that Frodo & Sam had to cross to reach Mount Doom
// places that are not cities
"Emyn Muil", // the rocky region that Sam & Frodo climb through after leaving the Fellowship
"Fangorn Forest", // the forest where Treebeard (and the other Ents) live
"Dagorlad", // great plain/swamp between Emyn Muil & Mordor where a great battle was fought long ago
"Weathertop", // the tower between Bree and Rivendell where Aragorn and the Hobbits take refuge
"Gladden Fields", // this is where the Ring is lost in the River Anduin, after Isildur is ambushed and killed by Orcs
"Entwash River", // a river through Rohan, which flows through Fangorn Forest
"River Isen", // river through the Gap of Rohan; Theoden's son was slain in a battle here.
"The Black Gate", // huge gate to Mordor that Aragorn and company attack as the ring is destroyed
"The Old Forest", // a forest to the west of the Shire (adventures there were removed from the movie)
"Trollshaws", // area to the west of Rivendell that was home to the trolls that Bilbo met
"Pelennor Fields", // great plain between M. Tirith and Osgiliath; site of the Battle of M. Tirith
"Hollin", // the empty plains that the Fellowship crosses between Rivendell and Moria
"Mirkwood", // Legolas' forest home; Bilbo travels there in 'The Hobbit'.
"Misty Mountains", // the north-south moutain range that runs through Middle-earth
"Prancing Pony", // an inn in Bree where the hobbits tried to meet Gandalf, but meet Aragorn instead
// places from the Hobbit book and movies
"Laketown", // also called Esgaorth, it is the town of men on the Long Lake near Erebor
"Dale", // the town of men outside Erebor, destroyed by Smaug long before the Hobbit story
"Erebor", // the Elvish name for the Lonely Mountain, where the dwarves had their fortress
"Beorn's House", // Beorn is the shape-shifter who shelters the dwarf party
"Dol Guldur", // fortress in Mirkwood where Sauron, as the Necromancer, hid during most of the Hobbit
};
// Iluvatar, the creator of Middle-Earth
MiddleEarth::MiddleEarth(int xsize, int ysize, int num_cities, int seed) {
this->xsize = xsize;
this->ysize = ysize;
// set up the random number generator
gen.seed(seed == -1 ? random_device{}() : seed);
// count the number of cities in the array
this->num_city_names = all_city_names.size();
if (num_cities > num_city_names) {
cout << "There are only " << num_city_names << " city names, so "
<< num_cities << " cities cannot be created." << endl;
cout << "Exiting." << endl;
exit(0);
}
if (num_cities < 5) {
num_cities = 5;
}
// copy all the cities into a mutable vector
this->cities = vector<string>(all_city_names.begin(), all_city_names.end());
shuffle(cities.begin(), cities.end(), gen); // shuffle all the cities
cities.erase(cities.begin() + num_cities, cities.end()); // then remove the ones we won't be using
// compute random city positions
for (auto city : cities) {
xpos.emplace(city, (gen() / (double) gen.max()) * xsize);
ypos.emplace(city, (gen() / (double) gen.max()) * ysize);
}
// compute the 2-d distance array
// we assume that num_cities < xsize * ysize
for (auto city1 : cities) {
for (auto city2 : cities) {
distances[city1].emplace(city2, sqrt((xpos[city2] - xpos[city1]) * (xpos[city2] - xpos[city1]) +
(ypos[city2] - ypos[city1]) * (ypos[city2] - ypos[city1])));
}
}
}
// The Mouth of Sauron!
// Prints out info on the created 'world'
void MiddleEarth::print() {
cout << "there are " << num_city_names
<< " locations to choose from; we are using " << cities.size() << endl;
cout << "they are: " << endl;
for (auto city : cities) {
cout << "\t" << city << " # (" << xpos[city] << ", " << ypos[city]
<< ")" << endl;
}
}
// Prints a tab-separated table of the distances,
// which can be loaded into Excel or similar
void MiddleEarth::printTable() {
cout << "Table: " << endl << endl << "Location\txpos\typos\t";
for (auto city : cities) {
cout << city << "\t";
}
cout << endl;
for (auto city1 : cities) {
cout << city1 << "\t" << xpos[city1] << "\t" << ypos[city1] << "\t";
for (auto city2 : cities) {
cout << distances[city1][city2] << "\t";
}
cout << endl;
}
}
// This method returns the distance between the two passed cities.
// If we assume that the hash table (i.e. the map) is O(1),
// then this method call is also O(1)
float MiddleEarth::getDistance(const string& city1, const string& city2) {
return distances[city1][city2];
}
// Returns the list of cities to travel to.
// The first city is the original start point as well as the end point.
// The number of cities passed in does not include this start/end point
// (so there will be length+1 entries in the returned vector).
vector<string> MiddleEarth::getItinerary(unsigned int length) {
// check parameter
if (length >= cities.size()) {
cout << "You have requested an itinerary of " << length
<< " cities; you cannot ask for an itinerary of more than length "
<< cities.size() - 1 << endl;
exit(0);
}
length++; // to account for the start point
// we need to make a deep copy of the cities vector
vector<string> itinerary(cities.begin(), cities.end());
// shuffle, erase unneeded ones, and return the itinerary
shuffle(itinerary.begin(), itinerary.end(), gen);
itinerary.erase(itinerary.begin() + length, itinerary.end());
return itinerary;
}
topological.cpp
#include <iostream>
#include <fstream>
#include <stdlib.h>
#include <list>
#include <stack>
#include <string>
#include <map>
using namespace std;
/**
#date 11/16/2020
*/
/** #brief
*/
class Graph
{
public:
Graph(int vert);
/** #brief adds an edge to the list
* #param string v
* #param string w
* #param map<string, int> m
*
*/
void addEdge(string v, string w, map<string, int> m);
void printSort();
private:
int vertices;
list<int> *myList;
void sort(int v, stack<int> &myStack, bool visited[]);
map<int, string> myMap;
};
Graph::Graph(int vert) {
vertices = vert;
myList = new list<int>[vertices];
}
void Graph::addEdge(string v, string w, map<string, int> m) {
int loc1 = m[v];
int loc2 = m[w];
myMap[loc1] = v;
myMap[loc2] = w;
myList[loc1].push_back(loc2);
}
void Graph::sort(int v, stack<int> &myStack, bool visited[]) {
visited[v] = true;
list<int>::iterator i;
for(i = myList[v].begin(); i != myList[v].end(); ++i) {
if(!visited[*i]) {
sort(*i, myStack, visited);
}
}
myStack.push(v);
}
void Graph::printSort() {
stack<int> myStack;
bool *visited = new bool[vertices];
for(int i = 0; i < vertices; i++) {
visited[i] = false;
}
for(int i = 0; i < vertices; i++) {
if(visited[i] == false)
sort(i, myStack, visited);
}
while(myStack.empty() == false) {
int x = myStack.top();
string output = myMap[x];
cout << output << " ";
myStack.pop();
}
}
int main (int argc, char **argv) {
if ( argc != 2 ) {
cout << "Must supply the input file name as the one and only parameter" << endl;
return 1;
}
ifstream file(argv[1], ifstream::binary);
ifstream file1(argv[1], ifstream::binary);
if ( !file.is_open() ) {
cout << "Unable to open file '" << argv[1] << "'." << endl;
return 1;
}
string s1, s2;
int count = 0;
list <string> edges;
while(!file.eof()) {
file >> s1;
file >> s2;
if(s1 == "0" && s2 == "0") {
break;
}
edges.push_back(s1);
edges.push_back(s2);
}
file.close();
edges.sort();
edges.unique();
int size = edges.size();
map<string, int> myMap;
Graph myGraph(size);
list<string>::iterator i;
for(i = edges.begin(); i != edges.end(); i++) {
string s = *i;
myMap[s] = count;
count++;
}
while(!file1.eof()) {
file1 >> s1;
file1 >> s2;
if(s1 == "0" && s2 == "0") {
break;
}
myGraph.addEdge(s1, s2, myMap);
}
myGraph.printSort();
cout<<endl;
file1.close();
return 0;
}
You are confusing yourself. You have your solution in edges. There isn't a reason to read the data a second time. For example, you can simply output sorted/unique elements of edges, e.g. the modifications to your code are:
int main (int argc, char **argv) {
if ( argc != 2 ) {
cout << "Must supply the input file name as the one and only parameter" << endl;
return 1;
}
ifstream file(argv[1], ifstream::binary);
// ifstream file1(argv[1], ifstream::binary);
if ( !file.is_open() ) {
cout << "Unable to open file '" << argv[1] << "'." << endl;
return 1;
}
string s1, s2;
// int count = 0;
list <string> edges;
while(file >> s1 && file >> s2) {
if(s1 == "0" && s2 == "0") {
break;
}
edges.push_back(s1);
edges.push_back(s2);
}
file.close();
edges.sort();
edges.unique();
// int size = edges.size();
// map<string, int> myMap;
bool first = true;
for (const auto& n : edges) {
if (!first)
cout.put(' ');
cout << n;
first = false;
}
cout.put('\n');
// Graph myGraph(size);
// list<string>::iterator i;
// for(i = edges.begin(); i != edges.end(); i++) {
// string s = *i;
// myMap[s] = count;
// count++;
// }
//
// while(file1 >> s1 && file1 >> s2) {
// if(s1 == "0" && s2 == "0") {
// break;
// }
// myGraph.addEdge(s1, s2, myMap);
// }
//
// myGraph.printSort();
// cout<<endl;
// file1.close();
return 0;
}
(note: how while (!file.eof())) was replaced with while(file >> s1 && file >> s2))
Example Use/Output
With your sample data in dat/topological.txt, you would receive:
$ ./bin/topological dat/topological.txt
cs1110 cs2102 cs2110 cs2150 cs3330 cs4414
If you are having problems editing your code, then you can do things much easier with a std::set, e.g.
#include <iostream>
#include <fstream>
#include <string>
#include <set>
int main (int argc, char **argv) {
if ( argc != 2 ) {
std::cerr << "Must supply the input file name as the one and only parameter\n";
return 1;
}
std::set<std::string> strset {};
std::string s {};
std::ifstream f (argv[1]);
if (!f.good()) {
std::cerr << "file open failed.\n";
return 1;
}
while (f >> s && s != "0")
strset.insert(s);
bool first = true;
for (const auto& unique : strset) {
if (!first)
std::cout.put(' ');
std::cout << unique;
first = false;
}
std::cout.put('\n');
}
(same answer)
This is when i used the main you gave me:
enter image description here
This is when i added (Yes. after edges.unique(); you can simply do. bool first = true; for (const auto& n : edges) { if (!first) cout.put(' '); cout << n; first = false; } cout.put('\n');):
enter image description here
the first line on output is correct, i dont want the line under it
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 have written a program to help me keep track of finances, I am using an array of structs to sore all the information and write it to a file. However, every time I select the option to close the program, it crashes with two separate errors.
Edit
This error occurs without running anything in the code. I open the program, select exit, and CRASH # return 0;
Output-Debug
Exception thrown at 0x0121A2D0 in USAA_C.exe: 0xC0000005: Access violation writing location 0x0052004F.
Stack Trace
USAA_C.exe!std::_Container_base12::_Orphan_all() Line 222 C++
USAA_C.exe!std::_String_alloc<std::_String_base_types<char,std::allocator<char> > >::_Orphan_all() Line 671 C++
USAA_C.exe!std::_String_alloc<std::_String_base_types<char,std::allocator<char> > >::_Free_proxy() Line 647 C++
USAA_C.exe!std::_String_alloc<std::_String_base_types<char,std::allocator<char> > >::~_String_alloc<std::_String_base_types<char,std::allocator<char> > >() Line 611 C++
USAA_C.exe!std::basic_string<char,std::char_traits<char>,std::allocator<char> >::~basic_string<char,std::char_traits<char>,std::allocator<char> >() Line 1007 C++
USAA_C.exe!Transaction::~Transaction() Line 10 C++
[External Code]
USAA_C.exe!main(int argc, char * * argv) Line 583 C++
[External Code]
[Frames below may be incorrect and/or missing, no symbols loaded for kernel32.dll]
Structure
struct Transaction {
Transaction(){}
~Transaction() {}
int day;
int month;
int year;
char status;
string name;
string method;
string cat;
double amount;
double balance;
};
Initialization
const int maxRecs = 1200;
Transaction record[maxRecs];
Transaction temp[maxRecs];
The only code that runs from explicitly opening and closing.
PS: I am using VS 2015
#include <iostream>
#include <string>
#include <iomanip>
#include <fstream>
using namespace std;
struct Transaction {
Transaction(){}
~Transaction() {}
int day;
int month;
int year;
char status;
string name;
string method;
string cat;
double amount;
double balance;
};
int main(int argc, char **argv) {
int sel = 0; // Integer option selections
int c = 0; // For loop iterator
int i = 1; // iterator
int count = 0; // Counter
int numRecsYr = 0; // Counts number of records in year array
int day = 0; // System day
int month = 0; // Sytem month
int year = 0; // System year
int fileSize = 0;
int bytesRead = 0;
string filename1 = "usaa_c.dat"; // default data file name
const int maxRecs = 10; // Maximum number of records to load
const int MENU = 7; // Number of menu items
Transaction record[maxRecs]; // Array for transaction records
Transaction temp[maxRecs]; // Temp array for resolving pending transactions
string mMenu[MENU] = {
"Add Transaction\n",
"View Account\n",
"Resolve Pending Transactions\n",
"Calculate Interest\n",
"Export to CSV File\n",
"Save Data\n",
"Exit\n\n" };
ifstream inFile; // file input stream
ofstream outFile; // file output stream
// Initialize the Transaction arrays
for (c = 0; c < maxRecs;c++) {
record[c].day = 0;
record[c].month = 0;
record[c].year = 0;
record[c].status = ' ';
record[c].name = " ";
record[c].method = " ";
record[c].cat = " ";
record[c].amount = 0.0;
record[c].balance = 0.0;
temp[c].day = 0;
temp[c].month = 0;
temp[c].year = 0;
temp[c].status = ' ';
temp[c].name = " ";
temp[c].method = " ";
temp[c].cat = " ";
temp[c].amount = 0.0;
temp[c].balance = 0.0;
}
// Get time info
time_t rawtime = time(NULL);
struct tm* timeinfo = new tm;
localtime_s(timeinfo, &rawtime);
day = timeinfo->tm_mday;
month = timeinfo->tm_mon + 1;
year = timeinfo->tm_year + 1900;
// Set precision for monetary values
cout << setprecision(2) << fixed << showpoint;
// If a .dat does not exist create a new one
// Else, read data into array
do {
inFile.open(filename1, ios::binary);
if (!inFile) {
cout << "File does not exist!\n\n";
system("PAUSE");
break;
}
else {
inFile.seekg(0, inFile.end);
fileSize = (int)inFile.tellg();
inFile.seekg(0, inFile.beg);
for (c = 0; bytesRead < fileSize, c < maxRecs;c++) {
inFile.read(reinterpret_cast<char *>(&record[c]), sizeof(Transaction));
bytesRead += (int)inFile.gcount();
}
inFile.close();
file = true;
break;
}
} while (file != true);
// Count how many records are in the array
for (c = 0; c < maxRecs;c++) {
if (record[c].amount != 0.0) {
count++;
}
}
numRecsYr = count;
// Main Program
do {
system("CLS");
cout << endl << endl;
// Main Menu
cout << "Main Menu\n\n";
i = 1;
for (c = 0; c < MENU;c++) {
cout << i++ << " " << mMenu[c];
}
cin >> sel;
if (sel <= 0 || sel >= 8) {
// Validate input
cout << " - " << sel << " - is not a valid selection! Please try again!\n\n";
system("PAUSE");
break;
}
else if (sel == 1) {
// Add Transaction
}
else if (sel == 2) {
// View Account
}
else if (sel == 3) {
// Resolve Pending Transactions
}
else if (sel == 4) {
// Calculate Interest Rate
}
else if (sel == 5) {
// Export Data to CSV File
}
else if (sel == 6) {
// Save Data to File
do {
system("CLS");
cout << "Saving Data to File...\n\n";
outFile.open(filename1, ios::binary);
if (!outFile) {
cout << "There was an error opening the file!\n\n";
system("PAUSE");
break;
}
else {
for (c = 0; c < numRecsYr;c++) {
outFile.write(reinterpret_cast<char *>(&record[c]), sizeof(Transaction));
}
}
outFile.close();
file = true;
break;
} while (file != true);
}
else if (sel == 7) {
// Exit
cout << "Goodbye!\n\n";
}
} while (sel != 7);
return 0;
}
Your Transaction class contains non-POD data (string variables) but then with
inFile.read(reinterpret_cast<char *>(&record[c]), sizeof(Transaction));
you're trying to read them in from a file as if Transaction instances are simple binary blocks of data. They're not so that doesn't work. And in doing so you happen to be corrupting the string objects which in this case happens to cause a crash during the Transaction destructors when you exit the program.
You'll need to use a more sophisticated way to write and read the data to and from file - something that accesses the member variables individually and correctly.
i am creating a somekind of rpg battle, where the program reads the input from a .txt file. i created the code but when i want to start the battle, it gave me an error vector subscript out of range. can anyone help me how to fix this? thank you very much :) here is the code. I included everything just so you could get a full context but the main problem I believe is in my while loop in the main cpp, if you want to just skip down to there.
and so that we are on the same track, the content of the txt file for lamanite(hitpoints and regen points) is
8 2
7 3
6 1
for nephite its
10 3
12 4
11 5
here is my warrior.h file
#pragma once
#include <string>
using namespace std;
class warrior
{
public:
warrior ();
warrior (int h, int r);
int getDamage() const;
void takeDamage(int damage);
int getCurrentHP() const;
void regenerate();
string tostring(int h, int r);
private:
int HitPoints;
int RegPoints;
int damage;
};
here is my warrior cpp
#include "warrior.h"
#include <string>
#include <iostream>
warrior::warrior(int h, int r)
{
HitPoints = h;
RegPoints = r;
}
int warrior::getDamage() const
{
int damage = rand () % HitPoints;
return damage;
}
void warrior::takeDamage(int damage)
{
HitPoints = HitPoints - damage;
}
int warrior::getCurrentHP() const
{
return HitPoints;
}
void warrior::regenerate()
{
HitPoints = HitPoints + rand () % (RegPoints);
}
string warrior::tostring(int h, int r)
{
return 0;
}
my main file
#include <iostream>
#include <string>
#include <vector>
#include <fstream>
#include <sstream>
#include <cstdlib>
#include <ctime>
#include "warrior.h"
using namespace std;
void main ()
{
srand(time(0));
ifstream input1;
cout << "input file name nephite: ";
string filename;
cin >> filename;
input1.open(filename);
int HP1, RP1;
vector <warrior*> nephites;
while (input1 >> HP1 >> RP1)
{
nephites.push_back(new warrior(HP1, RP1));
}
cout << nephites.size() << endl;
ifstream input2;
cout << "input file name lamanite : ";
string filename2;
cin >> filename2;
input2.open(filename2);
int HP2, RP2;
vector <warrior*> lamanites;
while (input2 >> HP2 >> RP2)
{
lamanites.push_back(new warrior(HP2, RP2));
}
cout << lamanites.size() << endl;
cout << endl << "Battle" << endl;
warrior nephitesw = warrior (HP1,RP1);
warrior lamanitesw = warrior (HP2,RP2);
while ((nephites.size() > 0) && (lamanites.size() > 0))
{
int rN = rand () % nephites.size();
int rL = rand () % lamanites.size();
cout << rN << "xx" << rL << endl; // so that i know what rN and rL is
while((nephites[rN]->getCurrentHP() > 0) && (lamanites[rL]->getCurrentHP() > 0)) // the program can't execute this part of the code
{
nephites[rN]->takeDamage(lamanites[rL]->getDamage());
lamanites[rL]->takeDamage(nephites[rN]->getDamage());
if(lamanites[rL]->getCurrentHP() > 0)
{
lamanites[rL]->regenerate();
}
else
{
lamanites.erase(lamanites.begin() + (rL));
}
if(nephites[rN]->getCurrentHP() > 0)
{
nephites[rN]->regenerate();
}
else
{
nephites.erase(nephites.begin() + (rN));
}
}
cout << "NEP HP: " << nephites[rN]->getCurrentHP() << " " << "LAM HP: " << lamanites[rL]->getCurrentHP() << endl;
}
system ("Pause");
}
You have a while loop that tests for a certain properties of nephites[rN] and lamanites[rL]:
while((nephites[rN]->getCurrentHP() > 0) && (lamanites[rL]->getCurrentHP() > 0)
{
// ...
}
But inside that loop you might erase those elements:
{lamanites.erase(lamanites.begin() + (rL));}
// ...
{nephites.erase(nephites.begin() + (rN));}
At the very least, after one of those erase operations you'll be testing a different nephite or lamanite object on the next loop iteration (which may or may not be what you want), but if you've erased the last element in the container, you have the problem that the index is now out of range.
You are looping until either nephites[rN]->getCurrentHP() <= 0 or lamanites[rL]->getCurrentHP() <= 0. However, whichever one drops to 0 first will be deleted from the vector:
// ...
{lamanites.erase(lamanites.begin() + (rL));}
// ...
{nephites.erase(nephites.begin() + (rN));}
If rN == nephites.size() or rN == lamanites.size() (which will definitely happen when the size is 1 and may randomly happen earlier), this will cause you to index out of the vector when you test the loop.
To quickly solve the problem, move the code that removes the warrior(s) from the vector out of the loop:
while((nephites[rN]->getCurrentHP() > 0) && (lamanites[rL]->getCurrentHP() > 0))
{
nephites[rN]->takeDamage(lamanites[rL]->getDamage());
lamanites[rL]->takeDamage(nephites[rN]->getDamage());
if(lamanites[rL]->getCurrentHP() > 0)
{
lamanites[rL]->regenerate();
}
if(nephites[rN]->getCurrentHP() > 0)
{
nephites[rN]->regenerate();
}
}
cout << "NEP HP: " << nephites[rN]->getCurrentHP() << " " << "LAM HP: " << lamanites[rL]->getCurrentHP() << endl;
// *****
// Move the erasures out of the loop
// *****
if(lamanites[rL]->getCurrentHP() <= 0)
{
lamanites.erase(lamanites.begin() + (rL));
}
if(nephites[rN]->getCurrentHP() <= 0)
{
nephites.erase(nephites.begin() + (rN));
}