save and load c++ program - c++

Ok so I figured out and learned a lot of stuff today and I want to thank the community for that. I haven't had any bump in the roads for a few hours now but now I'm stuck.
The last bump in the road. Saving and Loading my program. I have no idea where to start. I looked at how fwrite... and fread... works and all the examples are for programs that aren't split. I don't know where to start with my files. I'll put up 2 functions. If someone can help me how to do save those I can probably figure out the rest.
in gradebook.h
class Student {
public:
string last;
string first;
int student_id;
};
class Course {
public:
string name;
int course_id;
vector <Student> students;
};
class Gradebook {
public:
Gradebook();
void addCourse();
void addStudent();
private:
vector <Course> courses;
};
in gradebook.cpp
void Gradebook::addCourse() {
int i, loop=0;
cout << "Enter Number of Courses: ";
cin >> loop;
for(i=0; i<loop; i++) {
//create newEntry to store variables
Course newEntry;
cout << "Enter Course ID: ";
cin >> newEntry.course_id;
cout << "Enter Course Name: ";
cin >> newEntry.name;
//set variables from newEntry in Courses
courses.push_back(newEntry);
}
}
void Gradebook::addStudent() {
int i, loop=0;
cout << "Enter Number of Students: ";
cin >> loop;
for(i=0; i<loop; i++) {
//create newEntry to store variables
Student newEntry;
cout << "Enter Student ID: ";
cin >> newEntry.student_id;
cout << "Enter Last Name: ";
cin >> newEntry.last;
cout << "Enter First Name: ";
cin >> newEntry.first;
//set variables from newEntry in Students
courses[0].students.push_back(newEntry);
}
}
So if a user was to input some variables in courses and students how would i use fwrite... to save the data?

I wouldn't recommend fwrite, instead look into <fstream>. ifstream, ofstream
Basic saving:
ofstream out("data.txt"); //save file data.txt
out << thedata; //use the << operator to write data
Basic loading:
ifstream in("data.txt"); //reopen the same file
in >> thedata; //use the >> operator to read data.

Here's some sample code that might help without solving the whole thing for you.
#include<iostream>
#include<string>
#include<vector>
#include<fstream>
class Student {
public:
Student()
: student_id(0)
{
}
Student(const std::string &f, const std::string &l, int id)
: first(f)
, last(l)
, student_id(id)
{
}
std::string last;
std::string first;
int student_id;
};
std::ostream &operator <<(std::ostream &os, const Student &s)
{
os << s.last << '\t'
<< s.first << '\t'
<< s.student_id << '\t';
return os;
}
std::istream &operator >>(std::istream &is, Student &s)
{
is >> s.last
>> s.first
>> s.student_id;
return is;
}
bool WriteIt(const std::string &sFileName)
{
std::vector<Student> v;
v.push_back(Student("Andrew", "Bogut", 1231));
v.push_back(Student("Luc", "Longley", 1232));
v.push_back(Student("Andrew", "Gaze", 1233));
v.push_back(Student("Shane", "Heal", 1234));
v.push_back(Student("Chris", "Anstey", 1235));
v.push_back(Student("Mark", "Bradtke", 1236));
std::ofstream os(sFileName);
os << v.size();
for (auto s : v)
os << s;
return os.good();
}
bool ReadIt(const std::string &sFileName)
{
std::ifstream is(sFileName);
int nCount(0);
is >> nCount;
if (is.good())
{
std::vector<Student> v(nCount);
for (int i = 0; i < nCount && is.good(); ++i)
is >> v[i];
if (is.good())
for (auto s : v)
std::cout << s << std::endl;
}
return is.good();
}
int main()
{
const std::string sFileName("Test.dat");
return !(WriteIt(sFileName) && ReadIt(sFileName));
}
Bonus points if you recognise who my "students" are. :-)

Related

How to print a string from an object?

I tried the below code to write an object to a dat file:
#include<iostream>
#include<fstream>
#include<string>
#include<string.h>
using namespace std;
class Student
{ //data members
int adm;
string name;
public:
Student()
{
adm = 0;
name = "";
}
Student(int a,string n)
{
adm = a;
name = n;
}
Student setData(Student st) //member function
{
cout << "\nEnter admission no. ";
cin >> adm;
cout << "Enter name of student ";
cin.ignore();
getline(cin,name);
st = Student(adm,name);
return st;
}
void showData()
{
cout << "\nAdmission no. : " << adm;
cout << "\nStudent Name : " << name;
}
int retAdmno()
{
return adm;
}
};
/*
* function to write in a binary file.
*/
void demo()
{
ofstream f;
f.open("student.dat",ios::binary);
for(int i = 0;i<4;i++)
{
Student st;
st = st.setData(st);
f.write((char*)&st,sizeof(st));
}
f.close();
ifstream fin;
fin.open("student.dat",ios::binary);
Student st;
while(!fin.eof())
{
fin.read((char*)&st,sizeof(st));
st.showData();
}
}
int main()
{
demo();
return 0;
}
But when I am executing the demo function I am getting some garbage values from the "student.dat"
file. I am creating a database and want to get the records but I am not able to get all the records in the dat file.
Please suggest a solution
You cannot write complex data types to a file in binary mode. They have some additional variables and functions inside,which you do not know or see. Those data types have some internal state that or context dependent. So, you cannot store in binary and then reuse it somewhere else. That will never work.
The solution is serialization/deserialization.
This sounds complicated, but is not at all in your case. It basically means that all your data from your struct shall be converted to plain text and put in a text-file.
For readin the data back, it will be first read as text, and then converted to your internal data structures.
And the default approach for that is to overwrite the inserter << operator and extractor >> operator.
See the simple example in your modified code:
#include<iostream>
#include<fstream>
#include<string>
#include<iomanip>
class Student
{ //data members
int adm;
std::string name;
public:
Student()
{
adm = 0;
name = "";
}
Student(int a, std::string n)
{
adm = a;
name = n;
}
Student setData(Student st) //member function
{
std::cout << "\nEnter admission no. ";
std::cin >> adm;
std::cout << "Enter name of student ";
std::getline(std::cin>> std::ws, name);
st = Student(adm, name);
return st;
}
void showData()
{
std::cout << "\nAdmission no. : " << adm;
std::cout << "\nStudent Name : " << name;
}
int retAdmno()
{
return adm;
}
friend std::ostream& operator << (std::ostream& os, const Student& s) {
return os << s.adm << '\n' << s.name << '\n';
}
friend std::istream& operator >> (std::istream& is, Student& s) {
return std::getline(is >> s.adm >> std::ws, s.name);
}
};
/*
* function to write in a binary file.
*/
void demo()
{
std::ofstream f("student.dat");
for (int i = 0; i < 4; i++)
{
Student st;
st = st.setData(st);
f << st;
}
f.close();
std::ifstream fin("student.dat");
Student st;
while (!fin.eof())
{
fin >> st;
st.showData();
}
}
int main()
{
demo();
return 0;
}

Copying a specific field from a vector into another vector

I am trying to make a basket system for a C++ program, and I am stuck with the task of obtaining the price from one vector in a separate class, and copying that price into the new "Basket" Vector. i have tried a number of workaround but I have gotten as far as having it return the error message that the identifier is undefined, even though the vector is public in the class.
the header file :
class Item {
private:
int _ItemNo;
string _category, _description;
double _price;
double _VAT = _price*0.2;
double _subtotal = _price + _VAT;
};
class ItemMenu {
public:
vector<Item> _Items;
ItemMenu();
void displayMenu();
};
//Class for ordering from the menu
class Ordering {
private:
vector<Item> _Basket;
int quantity;
double total;
public:
Ordering();
Ordering(int quantity, double total);
void placeOrder(const vector<Item> &Items);
The implementation file:
ItemMenu::ItemMenu() {
ifstream fin("Menu.txt");
if(fin) {
while(!fin.eof()) {
string _ItemNoTemp;
getline(fin, _ItemNoTemp, ':');
int _ItemNo = stoi(_ItemNoTemp);
string _category;
getline(fin, _category, ':');
string _description;
getline(fin, _description, ':');
string _priceTemp;
getline(fin, _priceTemp);
double _price = stod(_priceTemp);
if(!fin.eof()) {
_Items.push_back(Item(_ItemNo,
_category, _description, _price));
};
fin.peek();
}
fin.close();
}
}
//Method to display the each item
void ItemMenu::displayMenu() {
for(int i = 0; i < _Items.size(); ++i) {
_Items[i].display();
}
cout << endl;
}
Ordering::Ordering() { }
void Ordering::placeOrder() {
int select;
cout << "Please enter an item number: ";
cin >> select;
Item I;
i._subtotal = _Items[select]._subtotal;
_Basket.push_back(i);
}
It is in the ordering class that the basket vector is in, and I am trying to get the subtotal for the items, so that I may calculate the total by summing the values in the vector. This is also where the error saying that _Items is undefined appeared. I am new to programing and haven't really been able to find a clear source for how vectors work between classes depending on where they are declared.
Something like this should work
void Ordering::placeOrder(
const vector<Item>& items ) {
int select;
cout << "Please enter an item number: ";
cin >> select;
cItem i;
i._price = items[ select ]._price;
_Basket.push_back( i );
}
You don't actually pass an ItemMenu object to this function. That's why you are getting an undefined error.
Instead of this
void Ordering::placeOrder() {
int select;
cout << "Please enter an item number: ";
cin >> select;
_Basket.push_back(_Items[select]._subtotal);
}
You would want to do this
void Ordering::placeOrder(ItemMenu yourItemMenuVarible) {
int select;
cout << "Please enter an item number: ";
cin >> select;
_Basket.push_back(_Items[select]._subtotal);
}
then when you call it you would pass it the ItemMenu variable you defined and I think that should fix it.
I would also recommend you not have variables like the vector public, it not a very good practice for security reasons. Learning good habits now will help you in the future. The idea of keeping them private is called Encapsulation here are some sources on the topic
https://www.geeksforgeeks.org/encapsulation-in-c/
https://www.tutorialspoint.com/cplusplus/cpp_data_encapsulation.htm#:~:text=Encapsulation%20is%20an%20Object%20Oriented,from%20outside%20interference%20and%20misuse.&text=This%20means%20that%20they%20can,other%20part%20of%20your%20program.
Thanks for all the help guys i ended up fixing it with your help the code is below.
Header File:
class Ordering {
private:
vector<Item> _Basket;
int quantity;
double total;
public:
Ordering();
Ordering(int quantity, double total);
void placeOrder(vector<Item> Items);
};
Implementation:
Ordering::Ordering() { }
void Ordering::placeOrder(vector<Item> _Items) {
int select;
Item i;
char cont;
do{
cout << "Please enter an item number: ";
cin >> select;
i._ItemNo = _Items[select-1]._ItemNo;
i._description = _Items[select-1]._description;
i._subtotal = _Items[select-1]._subtotal;
_Basket.push_back(i);
cout << i._subtotal;
cout << "Do you want to add another Item? (y/n): ";
cin >> cont;
}while(cont == 'y' || cont == 'Y');
for (int i; i < _Basket.size(); i++) {
cout << _Basket[i]._ItemNo << ':' << _Basket[i]._description
<< ':' << char(156) << _Basket[i]._subtotal << endl;
};
}
Main:
int main() {
cout << "--------------------------------" << endl;
cout << "Billing Program" << endl <<
"--------------------------------" << endl;
Ordering start;
ItemMenu display;
display.displayMenu();
start.placeOrder(display._Items);
}

Creating a vector in class then using class object in function not working

I have a class Employees. I'm trying to make the user insert and delete an employee but it's not working. The size of the vectors should be 500.
class Employees{
public:
int maxx = 500;
vector<string> Surname;
vector<string> FirstName;
vector<string> birthdate;
int vacation[500];
public:
Employees() : Surname(500) {}
};
This is the function that inserts, but printing elements of the vectors is not working at all:
void Process(Employees ZZ){
string dateyear;
string datemonth;
string dateday;
int dateyear1;
int datemonth1;
int dateday1;
int Realage;
int Vacationi = 0;
for(int i = 0; i < 500; i++) {
string s;
cin >> s;
string d;
cin >> d;
string c;
cin >> c;
ZZ.Surname.push_back(s);
ZZ.FirstName.push_back(d);
ZZ.birthdate.push_back(c);
cout << endl << ZZ.Surname[1] << endl;
}
Now the delete function, if I input a string then search for it in the vector then get his index then delete, but the vector doesn't update any values.
void DeleteEmployee(Employees ZZ){
cout<< endl << ZZ.Surname[1] << endl ;
for (int i = 0; i < ZZ.Surname.size(); i++){
cout << ZZ.Surname[i] ;
}
cout << " delete employee";
string delete1;
cin >> delete1;
auto it = std::find(ZZ.Surname.begin(), ZZ.Surname.end(), delete1);
if (it == ZZ.Surname.end())
{
cout<< " name not in vector " << endl;
}
else
{
//auto index = distance(Names.begin(), find(Names.begin(), Names.end(), old_name_)));
//ZZ.Surname.erase(ZZ.Surname.begin()+index) ;
}
}
This is the main function, also the values of the vector are not printing:
int main()
{
Employees ZZ;
Process(ZZ);
DeleteEmployee(ZZ);
cout << "fyccck";
for (int i = 0; i < ZZ.Surname.size(); i++){
cout << ZZ.Surname[i] ;
}
}
There are a lot of things wrong with this code. But the particular issue you are asking about is caused by your functions passing the Employees object by value, so a copy is made, and any changes you make to the copy are not reflected in the original object in main().
You need to change the parameters to pass the Employees object by reference instead:
void Process(Employees &ZZ)
void DeleteEmployee(Employees &ZZ)
That being said, the whole design of the code is not good in general. The vectors are not being kept in sync properly, and for that matter you are using more vectors then you actually need, 1 single vector will suffice. And Process() and DeleteEmployee() should be members of the Employees class, not separate functions. And they are both accessing out-of-bounds of the Surname vector.
I would suggest completely rewriting the code from scratch, for instance something more like this:
struct Employee{
string Surname;
string FirstName;
string BirthDate;
int Vacation;
string DisplayName() const { return Surname + ", " + FirstName; }
};
class Employees{
public:
static const int maxx = 500;
vector<Employee> employees;
Employees() { employees.reserve(maxx); }
bool Add(const Employee &e);
bool Delete(string Surname, string FirstName);
};
bool Employees::Add(const Employee &e) {
if (employees.size() < maxx) {
employees.push_back(e);
return true;
}
return false;
}
bool Employees::Delete(string Surname, string FirstName) {
auto it = std::find_if(employees.begin(), employees.end(),
[&](const Employee &e){
return e.Surname == Surname && e.FirstName == FirstName;
}
);
if (it != employees.end()) {
employees.erase(it);
return true;
}
return false;
}
int main()
{
Employees ZZ;
for(int i = 0; i < Employees::maxx; ++i) {
Employee e;
cin >> e.Surname;
cin >> e.FirstName;
cin >> e.BirthDate;
e.Vacation = 0;//cin >> e.Vacation;
ZZ.Add(e);
cout << endl << e.DisplayName() << endl;
}
cout << " delete employee";
string Surname, FirstName;
if (cin >> Surname >> FirstName) {
if (ZZ.Delete(Surname, FirstName)) {
cout << " name deleted from vector " << endl;
} else {
cout << " name not in vector " << endl;
}
}
cout << "fyccck";
for (auto &e : ZZ.employees) {
cout << e.DisplayName() << endl;
}
return 0;
}

class pointer unitialized local variable

Recently in my c++ class we have learned about pointers and classes.
I'm trying to make a program that has a class Student, which we will point to give each student a name and test score.
After entering both name and test score, they are sorted and then listed in order of highest to lowest.
I believe all my syntax to be correct, however I am still learning. The problem I am having is that the first time I use my class I get an uninitialized local variable error, any help on how to fix this?
#include "stdafx.h"
#include <iostream>
#include <string>
#include <array>
using namespace std;
class Student {
private:
double score;
string name;
public:
void setScore(double a) {
score = a;
}
double getScore() {
return score;
}
void setName(string b) {
name = b;
}
string getName() {
return name;
}
};
void sorting(Student*, int);
int main()
{
Student *students;
string name;
int score;
int *count;
count = new int;
cout << "How many students? ";
cin >> *count;
while (*count <= 0) {
cout << "ERROR: The number of students must be greater than 0.\n";
cin >> *count;
}
for (int i = 0; i < *count; i++) {
cout << "Please enter the students name: ";
cin >> name;
students[i].setName(name);
cout << "Please enter " << students[i].getName() << "'s score: ";
cin >> score;
while (score < 0) {
cout << "ERROR: Score must be a positive number.\n";
cin >> score;
}
students[i].setScore(score);
}
sorting(students, *count);
for (int i = 0; i < *count; i++) {
cout << students[i].getName() << ": " << students[i].getScore() << endl;
}
system("PAUSE");
return 0;
}
void sorting(Student *s, int size) {
for (int i = 0; i < size; i++) {
for (int j = i; j < size; j++) {
if (s[j].getScore() > s[(j + 1)].getScore()) {
int tmp = s[(j + 1)].getScore();
s[(j + 1)].setScore(s[j].getScore());
s[j].setScore(tmp);
string tmp1 = s[(j + 1)].getName();
s[(j + 1)].setName(s[j].getName());
s[j].setName(tmp1);
}
}
}
}
First off, your Student class can be simplified to this:
struct Student {
double score;
std::string name;
};
Because the accessors do absolutely nothing. I've also added the std:: prefix because using namespace std is considered a bad practice.
Now, instead of using the pointer to store the students, include vector and use that:
std::cout << "How many students? ";
int count;
std::cin >> count;
std::vector<Student> students(count);
The loading routine can also be simplified given the absence of accesors:
for (auto& student : students) {
std::cout << "Please enter the students name: ";
std::cin >> student.name;
std::cout << "Please enter " << student.name << "'s score: ";
std::cin >> student.score;
while (score < 0) {
std::cout << "ERROR: Score must be a positive number.\n";
std::cin >> student.score;
}
}
And actually once you have that, you could just put it in istream& operator>>(istream&, Student&) and reduce it to:
std::copy_n(std::istream_iterator<Student>(std::cin), students.size(), students.begin());
No need now for temporary variables anymore (and even if you want to use them, they should be defined just before the use, so inside of the loop).
The last thing is your sorting routine. First off, there's std::sort that you can use instead if you simply provide a comparator:
std::sort(
begin(students),
end(students),
[](Student const& a, Student const& b) { return b.score < a.score; }
);
If you insist on writing the sorting routine yourself, at least use std::swap.

Printing different strings for reading different object variables

I wish to output different string for reading variables. For example, below, I wish to print Enter english marks before reading english marks using eng.setmarks(). Please suggest a way to implement this.
Here is my code: (look at for loop below)
#include <iostream>
#include <cstring>
using std::cin;
using std::cout;
class student {
char name[20];
int age;
class marks {
int marks;
public:
void setmarks( int x) {
marks = x;
}
int getmarks() {
return marks;
}
};
public:
marks eng, math, phy, chem, cs; // nested objects are public
void setname( char* n) {
strncpy( name, n, 20);
}
char* getname() {
return name;
}
void setage( int a) {
age = a;
}
float total() {
size_t total = eng.getmarks() + math.getmarks() +
phy.getmarks() + chem.getmarks() + cs.getmarks();
return total/500.0;
}
};
int main() {a
student new_stud;
char temp[20];
cout << "Enter name: ";
cin >> temp;
cin.get( temp, sizeof(temp));
new_stud.setname(temp);
int age;
cout << "Enter age: ";
cin >> age;
new_stud.setage( age);
for( size_t i = 0; i < 5; ++i) {
// I wish to output: "Enter marks in" + subject_name, but harcoding it seems tedious
}
cout << "\nTotal Percentage: " << new_stud.total();
return 0;
}
So if I understand correctly, you would like to print out the name of the variable which you are about to read into. Now this can't be done on the way you want it. The best thing you can do is make an array of subject names, and an array of marks.
string[5] Subjects = {"Maths", "English", "Chemistry", "Physiscs", "Computer Sciences"};
marks[5] Marks;
for(int i=0;i<5;i++) {
cout << "Please enter marks in " << Subjects[i] << ":" << endl;
int a;
cin >> a;
Marks[i].setmarks(a);
}
You could also make the marks class have a field subject name, and give it a function inputfromuser(), like this:
class marks {
int marks;
string subjectName;
public:
void setmarks( int x) {
marks = x;
}
int getmarks() {
return marks;
}
void inputfromuser() {
cout << "Please enter marks in " << subjectName << ":" << endl;
cin >> marks;
}
};
Sorry for me using the std::string type, I am not very comfortable with the raw char[] way to handle texts.