I am working on a car rental program, and in it I need to be able to access a vector of the cars and prices from another class in order to make the receipt. Except every time I try to access the vector, there is nothing in it. How can I access the vector with the data in it?
#include <iostream>
#include <vector>
#include <string>
#include <fstream>
using namespace std;
const string SPORTS_CARS = "sports.dat";
class InventoryItem
{
public:
InventoryItem() {};
~InventoryItem() {};
friend class Cart;
vector<string> listOfCars;
vector<float> listOfPrices;
void readSports()
{
string car;
float price;
ifstream input(SPORTS_CARS);
if (input.is_open())
{
while (!input.eof())
{
getline(input, car);
input >> price;
input.ignore();
listOfCars.push_back(car);
listOfPrices.push_back(price);
}
input.close();
}
}
};
class Cart
{
public:
Cart() {};
~Cart() {};
void select()
{
InventoryItem a;
for (int i = 0; i < a.listOfCars.size(); i++)
{
cout << a.listOfCars[i] << endl;
}
}
};
int main() {
InventoryItem item;
item.readSports();
Cart cart;
cart.select();
}
The problem is that you create an empty 'Inventory' and then try to read it
InventoryItem a; <<<<==== empty
string carName;
cout << "What car do you want: ";
getline(cin >> ws, carName);
for (int i = 0; i < a.listOfCars.size(); i++) <<<====
You need to somehow have an 'loaded' Inventory and pass it as a parameter to this function. Or have the Cart constructor take an Inventory as an argument.
Its hard to propose an exact solution without seeing the whole code base.
OK now that you have made a good minmal example - heres how to fix it
void select(InventoryItem &inv)
{
for (int i = 0; i < inv.listOfCars.size(); i++)
{
cout << inv.listOfCars[i] << endl;
}
}
and in main
cart.select(item);
Maybe this is just an English language thing , but calling the inventory 'InventoryItem' is odd. 'InventoryItem' suggests one thing thats in the inventory. I would expect to see an 'Inventory' class that contains 'InvertoryItem's - of maybe just 'Car' objects
Related
I am learning c++ and have a trouble in file handling. I am writing a code as a homework where i have to write objects into a file and then read those objects as array from the file at once. Here is my code:
#include <iostream>
#include <fstream>
using namespace std;
class Records{
char* name;
int roll;
public:
Records()
{
name = new char[20];
}
void setData()
{
cout<<"Enter name: "<<endl;
cin>>name;
cout<<"Enter roll"<<endl;
cin>>roll;
}
char* getname()
{
return name;
}
int getRoll()
{
return roll;
}
void operator = (Records& no)
{
name = no.name;
roll = no.roll;
}
};
int main()
{
int i =0 ;
Records rec;
rec.setData();
Records::increase();
ofstream fout;
fout.open("file.txt", ios::app);
fout.write((char*)&rec, sizeof(rec));
fout.close();
Records* results = new Records[20];
Records rec1;
ifstream fin;
fin.open("file.txt", ios::in);
while(!fin.eof())
{
fin.read((char*)&rec1, sizeof(rec1));
results[i] = rec1;
i++;
}
fin.close();
cout<<results[0].getRoll();
return 0;
}
So basically, I made a Records class and store its object in a file. That works fine but I faced problem while taking data from file. It is not showing anything or sometimes showing garbage value. Anyone have better idea please hep me.
Thanks in advance!
First, you have to open file in binary mode for read and write.
std::ofstream fou("out_filename",std::ofstream::binary);
std::ifstream fin("in_filename", std::ifstream::binary);
Secondly, you assign operator=() is problematical. It assigns two records using the same address. Therefore in the reading process, all 20 elements in result[i] were all sharing the address of rec1::name. You have to correct the operator=() by copying contents of name.
This is not good.
void operator = (Records& no)
{
name = no.name;
roll = no.roll;
}
Rewrite as follows:
Edit: since your objects are all initially assigned with its memory. The new allocation is not necessary.
Records& Records::operator=(const Records& no)
{
// this->name = new char [20];
std::copy_n(no.name, 20, this->name); // include <algorithm>
roll = no.roll;
return *this; // return current object for another =.
}
Finally, add a destructor
Records::~Records() {
delete [] this->name; }
Good luck!
After fixed some other errors, I post this final version for you reference. Note that this project cannot use dynamic allocation for the field "name". Using dynamic allocation, the 20-byte of "name" is not counted as the size of class Records, and the pointer itself is not transferable. It causes read/write error in the field "name".
#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;
class Records{
char name[20];
int roll;
public:
Records()
{
// name = new char[20];
}
void setData()
{
cout<<"Enter name: "<<endl;
cin>>name;
cout<<"Enter roll"<<endl;
cin>>roll;
}
const char* getname() const
{
return name;
}
int getRoll() const
{
return roll;
}
Records& operator = (const Records& no)
{
std::copy_n(no.name, 20, this->name);
roll = no.roll;
return *this;
}
};
int main()
{
int i =0, c ;
std::string a;
Records rec;
ofstream fout;
fout.open("file.txt", std::ofstream::binary);
c = 0;
while (1)
{
std::cout << "Input record [" << c << "] ? (y/n) ";
std::cin >> a;
if (a[0]=='y' || a[0]=='Y')
{
rec.setData();
fout.write((char*)&rec, sizeof(rec));
++c;
}
else break;
}
fout.close();
// output
Records* results = new Records[20];
Records rec1;
ifstream fin;
fin.open("file.txt", std::ifstream::binary);
while(!fin.eof())
{
fin.read((char*)&rec1, sizeof(rec1));
results[i] = rec1;
i++;
}
fin.close();
// eidt to print all records
for (int j=0; j<(i-1); j++)
{ std::cout << "record # = " << j << std::endl;
std::cout << " name = " << results[j].name;
std::cout << " roll = " << results[j].roll << std::endl;
}
return 0;
}
A test run
$ ./a.exe
Input record [0] ? (y/n) y
Enter name:
aaaa
Enter roll
1234
Input record [1] ? (y/n) y
Enter name:
bbbb
Enter roll
2345
Input record [2] ? (y/n) y
Enter name:
cccc
Enter roll
3456
Input record [3] ? (y/n) n
1234
I am working on a little game and I want to make a leaderboard. I have class leaderboard and I am creating dynamic table, depending on how many players in the leaderboard.txt are. So that's one while eof loop. Then i want to asign names and points to these dynamic tables in leaderboard class. Problem is that i get random numbers instead of names and points. For me the code looks good. Any help?
class Leaderboard
{
int max_counter;
int counter;
int *points;
string *name;
string filename;
public:
Leaderboard(string n_file)
{
counter = 0;
filename = n_file;
}
string get_file(){return filename;}
void set_counter(int n_counter)
{
max_counter = n_counter;
points = new int[n_counter];
name = new string[n_counter];
}
void add_value(string n_name, int n_points)
{
name[counter] = n_name;
points[counter] = n_points;
counter++;
}
void show()
{
for(int i=0;i<max_counter;i++)
{
cout << name[i] << " " << points[i] << endl;
}
}
};
AND main:
Leaderboard *top = new Leaderboard("leaderboard.txt");
fstream file;
file.open(top->get_file(), ios::in);
if(file.good())
{
string name;
int points;
int counter = 0;
while(!(file.eof()))
{
file >> name >> points;
counter++;
}
counter--;
top->set_counter(counter);
while(!(file.eof()))
{
file >> name >> points;
top->add_value(name,points);
}
cout << "Dodano pomyslnie" << endl;
system("pause");
top->show();
file.close();
}
else cout << "Blad z plikiem!" << endl;
delete top;
break;
A couple of errors
while(!(file.eof()))
{
file >> name >> points;
counter++;
}
should be
while (file >> name >> points)
{
counter++;
}
Second error, you can't expect the file to magically go back to the beginning just because you want it to. You have to tell it to.
while (file >> name >> points)
{
...
}
file.clear(); // clear error state
file.seekg(0); // go to beginning of file
while (file >> name >> points)
{
...
}
Allow me to suggest that the general approach you're using here is open to considerable improvement.
Right now, our main knows (and has to know) a great deal about the internals of the Leaderboard to do its job.
It would be better if that were not required. The Leaderboard itself should be the only part that knows about its internals.
Let me go a bit further though: a leaderboard is basically just a collection of scores. It shouldn't know or care about the internal details of an individual score either.
Finally, let me suggest that you consider using a container from the standard library. In your case, it appears that std::vector will work quite nicely.
#include <iostream>
#include <vector>
#include <iterator>
#include <vector>
#include <fstream>
#include <algorithm>
class score {
std::string name;
int points;
public:
friend std::istream& operator>>(std::istream& is, score& s) {
return is >> s.name >> s.points;
}
friend std::ostream& operator<<(std::ostream& os, score const& s) {
return os << s.name << ": " << s.points;
}
};
class leaderboard {
std::vector<score> scores;
public:
friend std::istream& operator>>(std::istream& is, leaderboard& l) {
std::copy(
std::istream_iterator<score>(is), std::istream_iterator<score>(),
std::back_inserter(l.scores));
return is;
}
friend std::ostream& operator<<(std::ostream& os, leaderboard const& l) {
for (auto const& s : l.scores)
os << s << "\n";
return os;
}
};
int main() {
leaderboard scores;
std::ifstream in("leaderboard.txt");
in >> scores;
std::cout << "Top scores\n";
std::cout << scores;
}
Of course there's more that almost certainly should be done, such as sorting the scores in descending order by score, so the person with the top score shows up first--but that's kind of a separate issue.
I am working on an assignment that I am needing assistance on. I need to verify I did my array first (to make sure they are all pulling correctly) and then pass that array to another function that will loop through the array and look for a certain custID that will be entered into the console by the user. Here is my current code.
This is my singleton file
#include "MyDataStore.h"
#include <fstream>
MyDataStore * MyDataStore::iInstance;
//Declare private customer array..
Customer customers[5];
void getCustomerList(Customer[], int);
MyDataStore::MyDataStore()
{
getCustomerList(customers, 5);
}
MyDataStore * MyDataStore::GetInstance()
{
if (iInstance == NULL())
{
iInstance = new MyDataStore();
}
return iInstance;
}
void MyDataStore::getBooks(Book books[], int size)
{
ifstream input;
input.open("Books.txt");
string ISBN, title, author;
double price = 0.0;
int i = 0;
while (input >> title >> author >> ISBN >> price)
{
Book b = Book(ISBN, title, author, price);
if (i < size)
{
books[i] = b;
i++;
}
}
}
Customer MyDataStore::getCustomer(int custID) // need help here
{
//for (int i = -0; i < 5; i++) {
for (Customer c: customers)
{
if (custID = c.getCustID())
{
//custID = c.getCustID();
return c;
}
}
//}
//for range
//for each customer c in customers
//if custID = c.getCustID()
//return c
//
}
void getCustomerList(Customer customers[], int size)
{
//need help here
ifstream custfile;
custfile.open("Customer.txt");
int custID;
string firstName, lastName, city, street, state, zip;
Address address;
int i = 0;
while (custfile >> custID >> firstName >> lastName >> city >> street >> state >> zip)
{
Customer c = Customer(custID, firstName, lastName, address);
if (i < size)
{
customers[i] = c;
i++;
}
//Need to make the address part work
}
//load customer array
}
This is the source file it is being called to:
#include <iostream>
#include <string>
#include "Address.h"
#include "Book.h"
#include "Customer.h"
#include "MyDataStore.h"
#include <fstream>
using namespace std;
//Main function
void main()
{
MyDataStore * obj1 = MyDataStore::GetInstance();
MyDataStore * obj2 = MyDataStore::GetInstance();
//declare a book array --> this works great!
Book books[6];
//send array to get books
MyDataStore::getBooks(books, 6);
//loop through the filled in book array and just show the author
for (Book b: books)
{
cout << b.getTitle() << endl;
cout << b.getAuthor() << endl;
cout << b.getPrice() << endl;
}
//This will only print out the first line.
Customer c = MyDataStore::getCustomer(2345);
cout << c.print();
system("pause");
}
I hope this all makes sense. So I need to check to see if in the singleton if my
void getCustomerList(Customer customers[], int size)
is actually doing the array correctly (there are 5 items, all coming from the text file. I also need to then put then in the:
Customer MyDataStore::getCustomer(int custID)
But, I need to ask the console what the custID is and validate it, if it is what is listed in the text, then print it, if not then default it to 0 or say invalid.
I hope this all makes sense, thank you for any help!
Figured out, the rest of the code was correct, this is what I had to add to get it to work properly.
Inside the Singleton:
Customer MyDataStore::getCustomer(int custID)
{
for (Customer c : customers) {
if (custID == c.getCustID()) {
return c;
}
}
}
Inside of the source code:
int x = 0;
cout << "Please enter the customer ID!" << endl;
cin >> x;
Customer c = MyDataStore::getCustomer(x);
cout << c.print();
The stated problem is "Write a program that takes names and ages of 10 employees as input in a 2D char array and display their names in ascending order with respect to their ages".
I've pasted below what I have so far, but I don't know how to display the names in ascending order with respect to age. What am I missing?
#include<iostream.h>
#include<string.h>
void sort(int[],int);
void main(void)
{
char a[10][5],x;
int b[5],i,j;
for(j=0;j<=5;j++)
{
cout<<"Enter name of Employee:";
for(i=0;i<10;i++)
{
cin>>x;
x=a[j][i];
}
cout<<"Enter Employee's age:";
cin>>b[j];
cout<<endl;
}
sort(b,j);
cout<<"Name of Employee \t\t Age \n";
for(j=0;j<5;j++)
{
for(i=0;i<10;i++)
{
x=a[j][i];
cout<<"\t"<<x;
}
cout<<"\t\t"<<b[j]<<"\n";
}
}
void sort(int x[],int size)
{
int temp,i,j;
for(j=0;j<size;j++)
{
for(i=0;i<size;i++)
{
if(x[i]>x[i+1])
{
temp=x[i+1];
x[i+1]=x[i];
x[i]=temp;
}
}
}
}
I will point you in the right direction.
You should define struct to hold a Name and age pair, then make a comparison function.
Then you simply need to populate a vector of your structs then sort them using the sorting function provided by the standard library, iterate through the vector printing out the contents, you can define stream operator of the struct you made to simplify them.
http://www.cplusplus.com/doc/tutorial/structures/
http://en.cppreference.com/w/cpp/algorithm/sort
http://en.cppreference.com/w/cpp/container/vector
http://www.java2s.com/Code/Cpp/Overload/Overloadstreamoperator.htm
EDIT: and please for all that is good, use a std::string to hold the names.
http://www.cplusplus.com/reference/string/string/
using an char array like you are is pretty much deprecated.
I started writing this before the other solution, because I would rather see what C++ is capable of not what your lecture is feeding you.
#include <string>
#include <vector>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <fstream>
struct employee
{
employee(const std::string& name_, unsigned age_)
: name(name_), age(age_) {}
std::string name;
unsigned age;
};
std::ostream& operator<<(std::ostream& os, const employee& e)
{
os << e.name << " " << e.age;
return os;
}
bool comp_age(const employee& e1, const employee& e2)
{
return e1.age<e2.age;
}
int main()
{
std::vector<employee> employees;
employees.reserve(5);
for(unsigned i=0; i!=5; ++i)
{
std::string name;
unsigned age;
std::cout << "Name:" << std::flush;
std::cin >> name;
std::cout << "Age:" << std::flush;
if(!std::cin >> age)
{
std::cerr << "not an number" << std::endl;
--i;
continue;
}
//note you should catch any failure to parse to int here
employees.push_back(employee(name, age));
}
std::sort(employees.begin(), employees.end(), comp_age);
std::copy( employees.begin(), employees.end(),
std::ostream_iterator<employee>(std::cout, "\n"));
return 0;
}
So this is an alternative, but PLEASE learn the concepts I list above which constitutes this example.
You should start by changing void main to int main, because void main is not valid C++. Then you change the #includes to be real C++ header files not what you have:
#include <iostream>
#include <string>
Then you should give meaningful names to your variables. It's impossible to follow the code in a sea of as and bs.
Then you need to sort the employees by their age. You already have a sorting algorithm written there, so you only need to adapt it to swap all the employee data instead of swapping just their ages, while still doing the comparisons only on their age. This will be easier if instead of two separate arrays for the employee data, you kept instead a single array of a structure that holds both the name and age of the employee:
struct employee {
std::string name;
int age;
};
Once sorted, you can just loop through all the employees an print their names.
I believe there are a few more issues in the code, but they should be easy to fix with a good reference and some debugging time. If you have trouble, you can post a new question with what you've got so far, and explain what is stumping you.
This would all be much better if you just used the C++ standard library, but unfortunately some teachers decide to teach Crippled++ to their students instead of proper C++ :(
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
// treat an employee as a single unit
struct employee {
std::string name;
int age;
};
// a comparison function to compare two employees by their age
// should return true if the first one is younger than the second one
// this will be used for sorting later
bool is_younger(employee const& l, employee const& r) {
return l.age < r.age;
}
int main()
{
// a vector with 5 employees
std::vector<employee> employees(5);
for(j=0;j<=5;++j)
{
std::cout << "Enter name of Employee: "
// read the entire name at once
getline(std::cin, employees[j].name);
std::cout << "Enter Employee's age:";
// read the age
std::cin >> employees[j].age;
}
// sort all the employees using the comparison function written above
std::sort(employees.begin(), employees.end(), is_younger);
std::cout<<"Name of Employee \t\t Age \n";
for(j=0;j<5;++j)
{
std::cout << employees[j].name;
std::cout << "\t\t" << employees[j].age << "\n";
}
}
Use a std::multimap (a key/value store, fitting your needs), which is weakly sorted ascending by default. Your key is the age and the value is the name. For printing the values just use iterators. std::multimap is chosen because there could potentially be employees with the same age.
#include <iostream.h>
int main() {
int a;
int b;
int sum;
std::cout << "Enter two numbers" << std::endl;
std::cout << "Enter the value of a" << std::endl;
std::cin >> a;
std:: cout << "Enter the value of b" << std::endl;
std::cin >> b;
sum = a + b;
std::cout << sum << std::endl;
return 0;
}
guys, I'm reading from a file and input into a vector, but I keep getting a pop up box with: "vector employees out of range!" error. It is like if I'm trying to access pass the last index in the vector, but if that's the case I don't see... any help appreciated
text file:
123 vazquez 60000
222 james 100000
333 jons 50000
444 page 40000
555 plant 40000
code:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
struct employees { int id; string lname; double salary; };
void getData(vector<employees>& list, ifstream& inf);
int i = 0;
int main()
{
string filename("file2.txt");
vector<employees> list;
ifstream inf;
inf.open(filename);
getData(list, inf);
inf.close();
for(unsigned int j = 0; j < list.size(); j++)
{
cout << list[j].id << " " << list[i].lname << endl;
}
system("pause");
return 0;
}
void getData(vector<employees>& list, ifstream& inf)
{
int i = 0;
while(inf)
{
inf >> list[i].id >> list[i].lname >> list[i].salary;
i++;
}
}
When you pass list into getData(), it has zero elements in it. You then try to access the element at index i (starting at 0), but there is no such element, hence the error.
You need to insert new elements into the container; the easiest way to do this would be to create a temporary object, read the data into that object, and then insert that object into the container.
employee e;
while (inf >> e.id >> e.lname >> e.salary)
list.push_back(e);
Note that this also fixes your incorrect input loop. In your incorrect loop, the stream could reach EOF or otherwise fail during one of the reads in the loop, but you don't detect that until after you've incremented i.
In your while loop in getData, you need to push_back an employees each time. Or you can define the >> operator for your employees class, and you wouldn't even need the getData function, you could just past an istream_iterator into the vector constructor.
Example using istream_iterator:
#include <iostream>
#include <vector>
#include <string>
#include <iterator>
struct employee { int id; std::string lname; double salary; };
std::istream& operator>>(std::istream& is, employee& e) {
return is >> e.id >> e.lname >> e.salary;
}
int main() {
std::string filename("file2.txt");
std::ifstream inf;
inf.open(filename); //add error checking here
std::vector<employee> list((std::istream_iterator<employee>(inf)), std::istream_iterator<employee>());
for (std::vector<employee>::iterator iter = list.begin(); iter != list.end(); ++iter) {
std::cout << iter->id << " " << iter->lname << std::endl;
}
return 0;
}
list[i].lname should be list[j].lname