reading data from a file into an array of a class - c++

//Student file
#include <iostream>
#include <fstream>
#include <string>
#include <iomanip>
using namespace std;
#include "student.h"
#define cap 100
void main()
{ string s;
class student student[cap],l;
int i;
fstream f;
i=0;
cout << "Enter the file name: "; //Display to enter the file name
cin >>s;
f.open(s.data(),ios::in);
if(!f.is_open())
cout << "could not open file";
while(i<cap && !f.eof())
{ cout << "good";
student[i].get(f);
//Display if okay
if(f.good())
{
i++;
student[i].put(cout);
cout << i;
}
}
f.close();
}
class student
{
public:
student(); //Constructor without parameters
student(int,string,string,int,float); //Constructor with parameters
~student(); //Deconstructors
bool get(istream &); //Input
void put(ostream &); //Output
int read_array(string,int);
private:
int id,age;
float gpa;
string last,first;
};
student::student()
{
id = 0;
first = "null";
last = "null";
age = 0;
gpa = 0.0;
}
bool student::get(istream &in)
{
in >> id >> first >> last >> age >> gpa;
return(in.good());
}
void student::put(ostream &out)
{
out << id << first << last << age << gpa;
}
When i run this It displays the constructor values over, and over and the data from the file that should be going into the array and displaying them. I am not sure if I am doing the right way to put the data into the class array correctly.

Here's one problem:
if (f.good())
{
// student[i] has just been read from the file.
i++; // Increment counter.
student[i].put(cout); // Print whatever was in the next element.
cout << i;
}
The counter is incremented first, so student[i] refers to the element after the one that was just updated.

Related

Expression: Vector subscript out of range. Error 3 when using abort in console

I am unsure of what the issue is since I had no issues with my project the last time, I was working on it. I woke up this morning went to test what I had so far, and I've been hit with the "Expression: Vector subscript out of range" in an error screen right before it closes with error 3 when I click the abort button. It's a simple console RPG using C++ and I'm not sure what my vector is doing. It's involved in saving and loading characters to play the game with.
Game.h:
#pragma once
#include "Functions.h"
#include "Event.h"
#include <iostream>
#include <string>
#include <iomanip>
#include <ctime>
#include <vector>
#include <fstream>
using namespace std;
class Game
{
public:
Game();
virtual ~Game();
//Operators
//Functions
void mainMenu();
void InitGame();
void createNewCharacter();
void saveCharacter();
void loadCharacter();
void Travel();
//Accessors
inline bool getPlaying() const { return this->playing; }
//Modifiers
private:
int start;
bool playing;
//Character related
int activeCharacter;
string fileName;
vector<Character> character;
};
And these are the functions involved with the vector. in my Game.cpp
void Game::createNewCharacter() {
string name;
cout << endl;
cout << "enter name for new character: ";
getline(cin, name);
character.push_back(Character());
activeCharacter = character.size() - 1;
character[activeCharacter].Init(name);
}
void Game::saveCharacter() {
ofstream outFile(fileName);
if (outFile.is_open()) {
for (size_t i = 0; i < character.size(); i++) {
outFile << character[i].getAsString() << "\n";
}
}
outFile.close();
}
void Game::loadCharacter() {
ifstream inFile(fileName);
this->character.clear();
string name = "";
int gold = 0;
int distanceTrav = 0;
int level = 0;
int exp = 0;
int Str = 0;
int Con = 0;
int Dex = 0;
int hp = 0;
int movespeed = 0;
int statPoints = 0;
string line = "";
stringstream ss;
if (inFile.is_open()) {
while (getline(inFile, line)) {
ss.str(line);
ss >> name;
ss >> gold;
ss >> distanceTrav;
ss >> level;
ss >> exp;
ss >> Str;
ss >> Con;
ss >> Dex;
ss >> hp;
ss >> movespeed;
ss >> statPoints;
Character temp(name, gold, distanceTrav, level, Str, Con, Dex, hp, movespeed, statPoints);
this->character.push_back(Character(temp));
cout << "Character " << name << " loaded!\n";
}
}
inFile.close();
if (this->character.size() <= 0) {
throw "Error! No Characters Loaded or Empty File";
}
}
void Game::Travel() {
this->character[activeCharacter].travel();
Event ev;
ev.createEvent(this->character[activeCharacter]);
}
And this is my main:
#include "Game.h"
int main()
{
srand(time(NULL));
//int level = 12;
//int i = static_cast<int>((280 / 3) * ((pow(level, 3) - 6 * pow(level, 2)) + 17 * level - 12));
// cout << i << endl;
Game game;
game.InitGame();
Inventory inv;
//inv.addItem(Item());
//inv.debugPrint();
while (game.getPlaying()) {
game.mainMenu();
}
return 0;
}
In InitGame all I do is say welcome to the game, and the mainMenu is a case function that doesn't even get called before the error hits. If you need any more info, I will gladly provide it, I'm struggling with this probably obvious error for hours now.
In game.cpp you have
for (size_t i = 0; i < character.size(); i++) {
outFile << character[i].getAsString() << "\n";
}
shouldn't it be the activeCharacter var you created earlier.
for (size_t i = 0; i < activeCharacter; i++) {
outFile << character[i].getAsString() << "\n";
}
say character vector has 10 elements, character.size() will return to so character[10] would be the supposed 11th element(out of bounds) since its supposed to be zero indexed (hence the activeCharacter = character.size() - 1) you declared earlier.

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;
}

Garbage data when running this program (Student record program)

First off this is my own code, not copied.
The program is supposed to read student data from a "grades.txt" file which has marks for quizzes, finals etc and calculate the average, assign grades, and write the names and grades students who have passed and failed to "pass.txt" and "fail.txt".
Now the issue I face is that the total amount of students is 57. The program does stuff correctly for up to 39 students but it's always garbage values after that :(
#include <iostream>
#include <string>
#include <cmath>
#include <fstream>
#include <cstdlib>
using namespace std;
int counter; //counts the number of students
struct STUDENT
{
string firstname;
string lastname;
long idnumber;
int quiz1; //10%
int quiz2; //10%
int mid1; //15%
int mid2; //15%
double homework; //10%
double Final; //40%
double average; //to be calculated
char grade; //to be calculated
};
void Stcounter()
{
ifstream thing ("Grades.txt");
string dummy;
getline(thing,dummy); //for skipping the first line
string line;
int b=0;
while(getline(thing, line))
b++;
counter=b;
cout<<"Total number of students is "<< counter<<endl;
}
void read( STUDENT record[57])
{
float a;
ifstream thing("Grades.txt");
string d;
getline(thing,d);
for(int i=0;i<56;i++)
{
if( thing>> record[i].idnumber>>record[i].firstname>>record[i].lastname>>record[i].quiz1>>record[i].quiz2>>record[i].mid1>>record[i].mid2>>record[i].homework>>record[i].Final)
a=(record[i].quiz1/10)+(record[i].quiz2/10)+((record[i].mid1*15)/100)+((record[i].mid2*15)/100)+(record[i].homework/10)+((record[i].Final*40)/100);
record[i].average=a;
if(a>=85)
{
record[i].grade='A';
}
else if(a>=70)
{
record[i].grade='B';
}
else if(a>=55)
{
record[i].grade='C';
}
else if(a>=40)
{
record[i].grade='D';
}
else
{
record[i].grade='F';
}
}
}
void WriteToFile (STUDENT record[57])
{
ofstream p, f;
p.open("Pass.txt");
f.open("Fail.txt");
for (int i = 0; i <= 56; i++)
{
if (record[i].average >= 40)
{
p << record[i].idnumber << " " << record[i].firstname << " " << record[i].lastname << " passed with grade " << record[i].grade <<endl;
}
else
f << record[i].idnumber << " " << record[i].firstname << " " << record[i].lastname << " has failed"<<endl;
}
p.close();
f.close();
}
//This function counts how many students got a certain grade
void gradecount(STUDENT record[57])
{
int c1=0,c2=0,c3=0,c4=0,c5=0;
for(int i=0;i<57;i++)
{
if (record[i].grade=='A')
c1++;
else if(record[i].grade=='B')
c2++;
else if(record[i].grade=='C')
c3++;
else if(record[i].grade=='D')
c4++;
else
c5++;
}
cout<<c1<<" students got A"<<endl;
cout<<c2<<" students got B"<<endl;
cout<<c3<<" students got C"<<endl;
cout<<c4<<" students got D"<<endl;
cout<<c5<<" students got F"<<endl;
}
int main()
{
STUDENT record[57];
read(record);
WriteToFile (record);
Stcounter();
gradecount(record);
return 0;
}
If you didnt notice in your if statement
float a;
if(beggar>>record[i].idnumber>>record[i].firstname>>record[i].lastname>>record[i].quiz1>>record[i].quiz2>>record[i].mid1>>record[i].mid2>>record[i].homework>>record[i].Final)
a=(record[i].quiz1/10)+(record[i].quiz2/10)+((record[i].mid1*15)/100)+((record[i].mid2*15)/100)+(record[i].homework/10)+((record[i].Final*40)/100);
record[i].average=a;
it is giving you an error that you used the variable 'a' without it being initialized. So just when you declare a as a float assign it to 0 or something else

Making vector of objects by class

I have recently tried to learn how to create an object of vectors in order to represent objects of students including their names and grades. but when I wrote my program I got some errors regarding using &. I do not know what is the problem with my errors. could you please help me to fix it?
#include <iostream>
#include <vector>
#include <string>
using namespace std;
void printvector(const vector< student>&); // fill vector.fill in student information
void fillvector(vector< student>&); // print the information of all students
class student {
public:
student();
student(string, char);
~student();
string getName() ;
char getGrade() ;
void setName(string);
void setGrade(char);
private:
string newName;
char newGrade;
};
student::student() { newGrade = ' '; }
student::student(string name, char grade) {
newName = name;
newGrade = grade;
}
student::~student(){ }
string student::getName() { return newName; }
char student::getGrade() { return newGrade; }
void student::setName(string name) { newName = name; }
void student::setGrade(char grade) { newGrade = grade; }
int main() {
vector<student> myclass;
printvector(myclass);
fillvector(myclass);
return 0;
}
void fillvector(vector< student>& newmyclass) {
string name;
char grade;
int classsize;
cout << "how many students are in your class?";
cin >> classsize;
for (int i = 0; i < classsize; i++) {
cout << "enter student name";
cin >> name;
cout << "enter student grade";
cin >> grade;
student newstudent(name, grade);
newmyclass.push_back(newstudent);
cout << endl;
}
}
void printvector( vector< student>& newmyclass) {
unsigned int size = newmyclass.size();
for (unsigned int i = 0; i < size; i++) {
cout << "student name:" << newmyclass[i].getName() << endl;
cout << endl;
cout << "student grade" << newmyclass[i].getGrade() << endl;
cout << endl;
}
}
It seems you're printing your vector before filling it.. Is your problem fixed when you swap them around?
int main() {
vector<student> myclass;
printvector(myclass); // <--- These two lines should probably be swapped
fillvector(myclass); // <---
return 0;
}

Inserting info from a file into a struct

I want to extract data from a file and store them into the myWorld but my for loop doesn't work, the program doesn't loop one time once it gets to the for loop. I'm not sure what the problem is. This is my code so far.
#include <iostream>
#include <fstream>
#include <string>
#include <cstdlib>
using namespace std;
struct Country
{
double pop1950;
double pop1970;
double pop1990;
double pop2010;
double pop2015;
string name;
};
const int MAXCOUNTRIES = 300;
struct World
{
int numCountries;
Country countries[MAXCOUNTRIES];
} myWorld;
void printPop ();
int main ()
{
printPop();
return 0;
}
void printPop()
{
ifstream inFile("population.csv");
if (!inFile.fail())
{
cout << "File has opened successfully.";
}
if (inFile.fail())
{
cout << "File has failed to open.";
exit(1);
}
for (int i = 0; i < MAXCOUNTRIES; i++)
{
inFile >> myWorld.countries[i].pop1950 >> myWorld.countries[i].pop1970 >> myWorld.countries[i].pop1990
>> myWorld.countries[i].pop2010 >> myWorld.countries[i].pop2015;
getline (cin, myWorld.countries[i].name);
cout << "loop is running" << endl;
}
inFile.close();
}
I think your loop is running, its just waiting for user input here :
getline (cin, myWorld.countries[i].name);