I have been trying to get my code to dynamically allocate class objects to file to later read but having trouble with getting user input to save into each different object.
I'm trying to have the user input their names, ages and phone numbers and have it save to file where it can be read later hopefully using the same method to run through the file.
I tried using arrays but that can't save all three fields of the object. Is there a dynamic variable that can be used?
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <cassert>
using namespace std;
string mName, mID, mPhoneNumber;
int id = 0;
class Student
{
public:
string mName;
string mId;
string mPhoneNumber;
Student(string id = "", string name = "", string phone = "") : mId(id), mName(name), mPhoneNumber(phone)
{}
bool operator==(const Student& obj)
{
return (mId == obj.mId) && (mName == obj.mName) && (mPhoneNumber == obj.mPhoneNumber);
}
/*
* Write the member variables to stream objects
*/
friend ostream& operator << (ostream& out, const Student& obj)
{
out << obj.mId << "\n" << obj.mName << "\n" << obj.mPhoneNumber << endl;
return out;
}
/*
* Read data from stream object and fill it in member variables
*/
friend istream& operator >> (istream& in, Student& obj)
{
in >> obj.mId;
in >> obj.mName;
in >> obj.mPhoneNumber;
return in;
}
};
int main()
{
cin >> id;
Student stud1("1", "Jack", "4445554455");
Student stud2("4", "Riti", "4445511111");
Student stud3("6", "Aadi", "4040404011");
// open the File
ofstream out("students.txt");
// Write objects to file (targets to cout)
out << stud1;
out << stud2;
out << stud3;
out.close();
// Open the File
ifstream in("students.txt");
Student student1;
Student student2;
Student student3;
// Read objects from file and fill in data
in >> student1;
in >> student2;
in >> student3;
in.close();
// Compare the Objects
assert(stud1 == student1);
assert(stud2 == student2);
assert(stud3 == student3);
cout << stud1 << endl;
cout << stud2 << endl;
cout << stud3 << endl;
return 0;
}
You can make use of std::vector in the following manner:
std::vector<Student> my_students;
for (std::size_t i = 0; i < 3; i++) {
Student tmp;
in >> tmp;
my_students.push_back(tmp);
}
std::vector<Student> aVectOfStudents;
aVectOfStudents.emplace_back("","Jack", "4445554455");
aVectOfStudents.emplace_back("","Riti", "4445511111");
aVectOfStudents.emplace_back("","Aadi", "4040404011");
ofstream out("students.txt");
for(auto studIter = aVectOfStudents.begin(); studIter != aVectOfStudents.end(); ++studIter)
{
std::cout << "Insert Id for student: " << studIter->mName << "\n";
std::cin >> studIter->mId;
out<<*studIter;
}
out.close();
You could use the std::vector, to store the Student s and iterate through them to file out/inputs.
#include <vector>
int main()
{
// open the File
std::fstream file{ "students.txt" };
// vector of students
std::vector<Student> students{
{"1", "Jack", "4445554455"},
{ "4", "Riti", "4445511111"},
{"6", "Aadi", "4040404011"}
};
// iterate throut the objects and write objects(i.e. students) to the file
for(const auto& student: students)
file << student;
// reset the stream to the file begin
file.clear();
file.seekg(0, ios::beg);
// clear the vector and resize to the number of objects in the file
students.clear();
students.resize(3);
// read objects from file and fill in vector
for (Student& student : students)
file >> student;
file.close();
return 0;
}
Related
item,price,qty,ordno,trdno
abc,54,2,123,32
xyz,34,2,345,21
item: string (char[])
price,qty (int)
ordno (long long)
trdno (int)
Make a structure for above mentioned fields
Make a vector (array, or any other container type) to hold multiple instances of this structure
1: Read file
2: read line, split values
3: initialize above mentioned structure object
4: add this object of structure to container
5: when whole file is read.. iterate over the container and print each elements values (serialno, orderno, tradeno, price, qty, item)
I tried this and it is not working-
#include<bits/stdc++.h>
using namespace std;
struct item {
string name;
double price;
int quantity;
int order_no;
int trd_no;
};
int main()
{
int n;cin>>n;
string str, T;
ifstream read("input.txt");
while(getline(read,str))
{
cout<<str<<endl;
}
stringstream X(str); // X is an object of stringstream that references the S string
cout<<endl;
while (getline(X, T, ','))
{
cout << T << endl; // print split string
}
read.close();
return 0;
}
For the code that you are showing, you misplaced just one '}' after the first while. So the code will read in the first while-loop all lines of the file and is then empty. And, then you try to split the lines. This can of course not work.
If you move the closing bracket to in front of read.close(); then your code will work. Like this:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
using namespace std;
struct item {
string name;
double price;
int quantity;
int order_no;
int trd_no;
};
int main()
{
int n; cin >> n;
string str, T;
ifstream read("input.txt");
while (getline(read, str))
{
cout << str << endl;
stringstream X(str); // X is an object of stringstream that references the S string
cout << endl;
while (getline(X, T, ','))
{
cout << T << endl; // print split string
}
}
read.close();
return 0;
}
Caveat: this will not work, if the source file contains the header row! You can read this and throw it away, if needed.
If we follow the instruction of your homework, line by line, and assume that the first line contains header rows, then we would do like the following.
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
struct Item {
std::string name;
double price;
int quantity;
long long order_no;
int trd_no;
};
int main()
{
std::vector<Item> items;
std::string str, T;
std::ifstream read("input.txt");
// Read first line and ignore it
std::getline(read, str);
while (std::getline(read, str))
{
std::istringstream X(str);
Item tempItem;
getline(X, T, ',');
tempItem.name = T;
getline(X, T, ',');
tempItem.price = std::stod(T);
getline(X, T, ',');
tempItem.quantity = std::stoi(T);
getline(X, T, ',');
tempItem.order_no = std::stoll(T);
getline(X, T, ',');
tempItem.trd_no = std::stoi(T);
items.push_back(tempItem);
}
read.close();
for (const Item& item : items)
std::cout << item.name << ' ' << item.price << ' ' << item.quantity << ' '
<< item.order_no << ' ' << item.trd_no << '\n';
}
And, with a little bit more advanced C++, where we especially keep data and methods in a class, we could do the following:
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <vector>
#include <iomanip>
#include <algorithm>
#include <iterator>
// The item
struct Item {
std::string name{};
double price{};
int quantity{};
long long order_no{};
int trd_no{};
// Overwrite extraction operator for easier stream IO
friend std::istream& operator >> (std::istream& is, Item& i) {
char c;
return std::getline(is >> std::ws, i.name, ',') >> i.price >> c >> i.quantity >> c >> i.order_no >> c >> i.trd_no;
}
// Overwrite inserter for easier output
friend std::ostream& operator << (std::ostream& os, const Item& i) {
return os << "Name: " << i.name << "\tPrice: " << i.price << "\tQuantity: " << i.quantity << "\tOrder no: " << i.order_no << "\tTRD no: " << i.trd_no;
}
};
// The Container
struct Data {
std::vector<Item> items{};
// Overwrite extraction operator for easier stream IO
friend std::istream& operator >> (std::istream& is, Data& d) {
// Read header line and ignore it
std::string dummy; std::getline(is, dummy);
// Delete potential old data
d.items.clear();
// Read all new data from file
std::copy(std::istream_iterator<Item>(is), {}, std::back_inserter(d.items));
return is;
}
// Overwrite inserter for easier output
friend std::ostream& operator << (std::ostream& os, const Data& d) {
std::copy(d.items.begin(), d.items.end(), std::ostream_iterator<Item>(os, "\n"));
return os;
}
};
int main()
{
// Open file and check, if it could be opened
if (std::ifstream sourceFileStream("input.txt"); sourceFileStream) {
// Define container
Data data{};
// Read and parse complete source file and assign to data
sourceFileStream >> data;
// Show result
std::cout << data;
}
else std::cerr << "\n\nError: Could not open source file:\n\n";
}
How can I ignore the first line of the text file and start at the second line when I called it in the code? I was wondering how. Also, how can I sort the file according to first name, last name and grade? I just have the first name sorted but not the last name and grade accordingly. If you have any idea, I hope you can share it with me. Thanks for the help! Here's my code:
#include <iostream>
#include <fstream>
using namespace std;
struct studentRecord{
string lastname;
string firstname;
string grade;
};
int main(){
ifstream ifs("student-file.txt");
string lastname, firstname, grade, key;
studentRecord records[20];
if(ifs.fail()) {
cout << "Error opening student records file" <<endl;
exit(1);
}
int i = 0;
while(! ifs.eof()){
ifs >> lastname >> firstname >> grade;
records[i].lastname = lastname;
records[i].firstname = firstname;
records[i].grade = grade;
i++;
}
for (int a = 1, b = 0; a < 20; a++) {
key = records[a].firstname ;
b = a-1;
while (b >= 0 && records[b].firstname > key) {
records[b+1].firstname = records[b].firstname;
b--;
}
records[b+1].firstname = key;
}
for (int k = 0; k < 20; k++) {
cout << "\n\t" << records[k].firstname << "\t"<< records[k].lastname << "\t" << records[k].grade;
}
}
When I saw this post it reminded me of a similar task completed at uni. I have rewritten your code to perform the same task but using classes instead of structs. I have also included a way to sort the vector by using the function here.
I have included the "ignore first line" method #Scheff's Cat mentioned.
Here it is:
#include <iostream>
#include <fstream>
#include <sstream>
#include <limits>
#include <string>
#include <vector>
using namespace std;
class studentrecord{
string firstname, lastname, grade;
public:
studentrecord(string firstname, string lastname, string grade){
this -> firstname = firstname;
this -> lastname = lastname;
this -> grade = grade;
}
friend ostream& operator<<(ostream& os, const studentrecord& studentrecord) {
os << "\n\t" << studentrecord.firstname << "\t" << studentrecord.lastname << "\t" << studentrecord.grade;
return os;
}
};
void displayRecords(vector <studentrecord*> records){
for(int i = 0; i < records.size(); i++){
cout << *records[i];
}
}
int main(){
//read in file
ifstream infile;
infile.open("student-file.txt");
infile.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
if (!infile.is_open()){
cout << "Error opening student records file" <<endl;
exit(1);
}
vector <studentrecord*> records;
string firstname, lastname, grade;
while (infile >> firstname >> lastname >> grade;) {
records.push_back(new studentrecord(firstname, lastname, grade));
}
displayRecords(records);
return 0;
}
To sort the vector so that it prints in order of either first name, last name or grade I used the following functions:
bool sortfirstname(studentrecord* A, studentrecord* B) {
return (A->getfirstname() < B->getfirstname());
}
bool sortlastname(studentrecord* A, studentrecord* B) {
return (A->getlastname() < B->getlastname());
}
bool sortgrade(studentrecord* A, studentrecord* B) {
return (A->getgrade() < B->getgrade());
}
sort(records.begin(), records.end(), (sortfirstname));
sort(records.begin(), records.end(), sortlastname);
sort(records.begin(), records.end(), sortgrade);
If you wanted to sort by first name you would call the sort(records.begin(), records.end(), (sortfirstname)); function and then the displayrecords() function.
The advantage of using classes stored in vectors is that you don't have to state the size of the vector containing the details about students since you can keep adding information to the end of the vector using the vector.push_back() function. It also makes sorting the data contained easier.
If anything isn't clear, let me know and I can give you a hand.
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'm working on this program that is to help manage a DVD rental store. What I have to do is take a text that contains info about DVD etc:
Mean girls; comedy; PG; 2009; Regina George; 12.07.2015;
The Conjuring; Horror; R; 2013; Sara Johnson; 16.05.2016;
Pokemon 2000; Kids; G; 2000; Ash Katchem; 15.04.2016;
etc..
And then takes this information and then reads it into an array and from there the array is read into the struct and then displayed in proper order like so:
Name: Mean Girls
Genre: Comedy
Rating: PG
etc...
This is my code so far:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
using namespace std;
struct dvd{
string name;
string genre;
string rating;
string released;
string renter;
string rentday;
void print();
bool read(ifstream & file);
};
void dvd::print(){
cout <<"Title: " << name << endl;
cout <<"Genre: " << genre << endl;
cout << "Rating: " << rating << endl;
cout << "Release date: " << released << endl;
cout << "Name of renter: " << renter << endl;
cout << "Date rented: " << rentday << endl;
}
bool dvd::read(ifstream & file)
{
getline(file, name, ';');
getline(file, genre, ';');
getline(file, rating,';');
getline(file, released, ';');
getline(file, renter, ';');
getline(file, rentday, ';');
return file.good();
}
int main() {
vector<dvd> dvds;
dvd dvd1;
ifstream file("DVD.txt");
if(! file.is_open()){
cout << "Failed to find input file" << endl;
return 1;
}
while(dvd1.read(file))
{ dvds.push_back(dvd1);
}
dvd1.print();
return 0;
}
So what I would like to do is have read the text file into the Array and from there read the Array into the struct. So instead of the text file reading into the vector I need it to read into the array and from there read the first line of the array (dvdArray[1]) into struct dvd and then print out that information using print function and then loop that until dvdArray[10] is read into struct dvd!
Thank you so much for your help! :)
Change
bool dvd::read(ifstream & file)
to
bool dvd::read(istream & file)
No other changes to its contents are required.
Then, take each line and put it into a std::istringstream, then pass it to dvd::read.
You should be able to figure out the rest on your own.
For simple reading from and writing to file, I would suggest overload << and >> for your struct class, in order to make the code easy to serialize and de-serialize in a readable fashion.
friend std::ostream& operator<< (std::ostream& stream, const dvd& dvdObj)
{
// your output stuff
// stream <<"Title: " << dvdObj.name << endl;
// ...
return stream;
}
friend std::istream& operator>> (std::istream& stream, dvd& dvdObj)
{
// your output stuff
// getline(stream, dvdObj.name, ';');
// ...
return stream;
}
Then,
// look for std::copy for reading directly into vector ... else
while( file >> dvd1 )
{
dvds.push_back(dvd1);
}
And,
for( const auto& dvd1: dvds )
{
std::cout << dvd1 ;
}
Basically I am trying to create a vector of objects but I have to create the objects with information read from a file using the overloaded input stream operator for my class Voter.
main:
#include <cstdlib>
#include <vector>
#include <string>
#include "Voter.h"
#include <iostream>
#include <fstream>
using namespace std;
int main(int argc, char** argv) {
int i = 0;
int idNumber;
string firstName;
string lastName;
string hasVoted;
vector<Voter> VoterVector;
ifstream inFile;
inFile.open("voters.txt");
if(!inFile){
cout << "Unable to open voters.txt" << endl;
}
inFile >> idNumber >> firstName >> lastName >> hasVoted;
while(inFile) {
Voter temp();
temp >> idNumber >> firstName >> lastName >> hasVoted;
VoterVector.push_back(temp);
inFile >> idNumber >> firstName >> lastName >> hasVoted;
}
return 0;
}
Voter class:
#ifndef VOTER_H
#define VOTER_H
#include <string>
using namespace std;
class Voter {
public:
Voter();
virtual ~Voter();
friend istream &operator>>(istream &in, Voter &v);
friend ostream &operator<<(ostream &out, Voter &v);
private:
int idNumber;
string firstName;
string lastName;
string hasVoted;
};
Voter::Voter() {
this->idNumber = 0;
this->firstName = '-none-';
this->lastName = '-none-';
this->hasVoted = 'FALSE';
}
Voter::~Voter() {
}
istream &operator>>(istream &in, Voter &v) {
in >> v.idNumber >> v.firstName >> v.lastName >> v.hasVoted;
return in;
}
ostream &operator<<(ostream &out, Voter &v) {
out << v.idNumber << endl << v.firstName << endl << v.lastName << endl << v.hasVoted << endl;
return out;
}
I keep getting errors with the way I create the objects and put them into the vector. I am pretty sure my overloading and reading from the file is done correctly, just not sure on the proper way to set up the vector of the objects. Any help is appreciated. Thanks!
Voter temp();
This is wrong. It declares a function.
Here's how you create a Voter object:
Voter temp;
Furthermore, you are doing strange things with that >> operator.
Why not simply:
int main()
{
vector<Voter> voterVector;
ifstream inFile("voters.txt");
if (!inFile) {
cout << "Unable to open voters.txt" << endl;
}
Voter temp;
while (inFile >> temp) {
voterVector.push_back(temp);
}
}