Reading data from file into a vector object - c++

My vector is not getting data from the file I have it retrieve. I created a class called Student, and needed to make a vector out of it to store multiple values for the students. The code worked on my original test file, but when I change the students, it errors out.
Here's the part that's in main:
vector<Student> studentVector; //creating a vector using the defined class Student
string userFile = "";
string filename = "";
int numStudents = 0; //total number of students
int numQuestions = 0; //total number of questions
string key = ""; //answer key
cout << "Enter the name of the file: ";
cin >> userFile; //get name of file from user
filename = checkFile(userFile, numQuestions, key); //gets info from file and returns the new file name to get student answers
fillVector(studentVector, filename, numStudents); //fills vector with values from file
Here's the function that reads the data:
void fillVector(vector<Student>& newStudentVector, string filename, int& numStudents) {
ifstream studentAnswers; //read mode file
string line = ""; //used to read lines
int id = 0;
string fName = ""; //first name
string lName = ""; //last name
string answers = "";
studentAnswers.open(filename); //opens file using filename passed into function
while (getline(studentAnswers,line)) {
++numStudents; //reads the number of lines in file
}
studentAnswers.close(); //closed file because it reached end of file
studentAnswers.open(filename); //reopens file
for (int i = 0; i < numStudents; i++) {
//reads file data
studentAnswers >> id;
studentAnswers >> fName;
studentAnswers >> lName;
studentAnswers >> answers;
Student newStudent(id, (fName + " " + lName), answers, 100.00, "A"); //creates a new object
newStudentVector.push_back(newStudent); //adds new vector with newStudent data
}
studentAnswers.close(); //close file
}

You have to open your string-name file like this :
studentAnswers.open(filename.c_str());
Try to loop through your vector like this :
getline(studentAnswers,line)
while (!studentAnswers.eof()) {
getline(studentAnswers,line)
++numStudents;
}

Assuming that you've implemented operator>>(std::istream&, Student&), then a fairly easy way to implement fillVector() is to use stream iterators.
void fillVector(std::vector<Student>& newStudentVector,
std::string filename, int& numStudents) {
std::ifstream studentAnswers(filename);
if (!studentAnswers) {
std::cout << "WARNING! studentAnswers file not found\n";
}
newStudentVector.assign(
std::istream_iterator<Student>(studentAnswers),
std::istream_iterator<Student>());
numStudents = newStudentVector.size();
}

Related

Parse (split) a txt file with a string and int in c++

im a Student and new to this site. I want to split my txt file with my highscore data back to my Highscore List.
The txt file stores my Highscore like name:score
My parsing is not working and i dont know why?
I just want to split it to name and score again and then put it in my HighscoreList.
If you have any question about the code just ask :)
#include "highscore.h"
highscore::highscore(){
}
struct highscore::Player{
string spielerName;
int score;
};
void highscore::writeHighscore(string name, int score ,int playerNumberx){
Player HighscoreListe[100];
for(int i=0;i<=99;i++){
HighscoreListe[i].score = {0};
}
for(int i=0;i<=99;i++){
HighscoreListe[i].spielerName = "leer";
}
HighscoreListe[playerNumberx].spielerName = name;
HighscoreListe[playerNumberx].score = score;
int i, j,temp;
string temp1;
ifstream myfile("scores.txt");
string line;
//heres the point where i need help!!
if (myfile.is_open()){
int z=0;
while(getline(myfile, line)){
string name1;
string score1;
int d = 20;
while(line[z] != ':'){
name1 += line[z];
z++;
}
z = z+2;
while(line[z] != '\0'){
score1 += line[z];
z++;
}
HighscoreListe[d].spielerName = name;
HighscoreListe[d].score = score;
d++;
}
myfile.close();
}else cout << "Unable to open file" << endl;
for(i = 0; i<100; i++) {
for(j = i+1; j<100; j++)
{
if(HighscoreListe[j].score < HighscoreListe[i].score) {
temp = HighscoreListe[i].score;
temp1 = HighscoreListe[i].spielerName;
HighscoreListe[i].score = HighscoreListe[j].score;
HighscoreListe[i].spielerName = HighscoreListe[j].spielerName;
HighscoreListe[j].score = temp;
HighscoreListe[j].spielerName = temp1;
}
}
}
ofstream myfilex("scores.txt");
if (myfilex.is_open()){
for(int i = 99;i>89;i--){
myfilex << HighscoreListe[i].spielerName << ":" << HighscoreListe[i].score<<endl;
}
myfilex.close();
}
else cout << "Unable to open file" << endl;
}
void highscore::readHighscore(){
string line;
ifstream myfile("scores.txt");
if (myfile.is_open()){
while(getline(myfile, line)){
cout << line << endl;
}
}
else cout << "Unable to open file" << endl;
}
Make a >> overload for highscore::Player.
In the >> overload
Use std::getline to read a line from the input stream.
Create a std::istringstream out of the line.
Use std::getline to read up to the : from the istringstream into a local string name;.
Use another std::getline to read the rest of the line into a string.
Convert the string into an int with std::stoi and store into a local int score;. Make sure you provide a pos argument.
Ensure that the entire string was converted by comparting the pos argument with the string's length.
If nothing went wrong, store name and score into the highscore::Player passed by the caller. Otherwise, set the failbit on the input stream with setstate
return the input stream.
Now the reading code should be something simple like
int scorecount = 0;
while (myfile >> HighscoreListe[scorecount])
{
scorecount++;
}

Text from file not reading into arrays

This portion of my program is intended to read in a list of names and grades of students, then average them together and display them.
I declared a function as such:
int loadStudentNamesGrades(string students[], int grades[][MAX_GRADES],
string fileName, int maxStudents);
Here is the Definition:
int loadStudentNamesGrades(string students[],
int grades[][MAX_GRADES],
string fileName,
int maxStudents)
{
ifstream inFile; // input file stream
string nameFile; // name of file
string studentName; // name of student
int numStudents = 0; // number of students initialized to 0
inFile.open(fileName); // open the file
if (!inFile)
{
cout << "Unable to Open File!\n";
system("PAUSE");
exit (EXIT_FAILURE);
}
for (int i = 0; i < maxStudents && (inFile >> studentName >> numStudents);
i++, numStudents++)
{
for (int j = 0; j < MAX_GRADES; j++)
{
inFile >> grades[i][j];
}
students[i] = studentName;
}
inFile.close();
return numStudents;
}
When I try to run my program, my menu displays but none of the values from the text file populate. As far as I know my file is opening properly because it does not return an error.
It looks like it reads into the arrays, but you are not returning those. Try passing your arrays by reference, something like this:
int loadStudentNamesGrades(string (&students)[10], int (&grades)[10][MAX_GRADES],
string fileName, int maxStudents)
You could also think about using vectors instead of arrays.

read line from text then copy into structure

So I understand the basic concept of reading a text file line by line using a while loop, now my question is how do I read each line and then put the contents of those lines into a variable that is part of a structure?
I figured out how to write my text to a file but not how to store the information from that same file so here is what I have so far but it does not seem to work:
This works:
void save(string fileName)
{
Container *traverser = list;
ofstream file;
file.open(fileName);
while (traverser != NULL){
file << traverser->student->getFirstName() << endl;
file << traverser->student->getLastName() << endl;
file << traverser->student->getGrade() << endl;
file << traverser->student->getEdu() << endl;
traverser = traverser->next;
}
}
This doesn't:
void load(string fileName)
{
Container *traverser;
Container* c;
Student *s;
string fname, lname;
int grade;
int edu;
ifstream file;
file.open(fileName);
string line;
while (getline(file, line)){
file >> fname;
file >> lname;
file >> grade;
file >> edu;
s = new Student(fname, lname, grade, edu);
c = new Container();
c->student = s;
}
}
Is it something with my syntax or am I doing it wrong all together?
The program essentially asks for the students first and last names, grade, and education then it stores that into a text file, then it is supposed to load the information from the text file back into the program (I didn't post the whole code because there is a lot).
Thanks!
Additional info: list is a linked list of Structures (students)
I suspect your data is in one line
while (getline(file, line)){
istringstream lstr(line);
lstr >> fname;
lstr >> lname;
lstr >> grade;
lstr >> edu;
s = new Student(fname, lname, grade, edu);
c = new Container();
c->student = s;
}
This could already do the job.
Edit: You might want to #include <sstream>

std::out_of_range at memory location error at getline

I'm very new to c++ there is a good bit of code here, so im going to do my best to condense it to the problem area. when I try to get user input using getline im getting this error. Since i don't expect spaces in the file names(i made the files)i use cin << which worked fine, but then got the same error when trying to read the file. the code is as follows
// includes here
using namespace std;
//other prototypes here
string getUserDataFromFile(vector<int>&, int&, string);
int main()
{
vector<int> numbers;
numbers.reserve(50);
int numberOfElements = 0;
int number = 0;
int numToFind = 0;
int numberPosition = -1;
int useFile = 0;
string filename = "";
string fileReadMessage = "";
string output = "";
string outFilename = "";
cout << "Would you like to load the data from a file?(1 for yes 0 for no)";
cin >> useFile;
cin.ignore(INT_MAX, '\n');
//get user data for manual input
if(useFile == 0)
{
//code here for manual input(works fine)...
}
//get userdata for file input
else
{
cout << "Please Enter the file path to be opened" << endl;
//fixed after adding cin.ignore(INT_MAX, '\n');
//see next function for another problem
getline(cin, filename);
fileReadMessage = getUserDataFromFile(numbers, numToFind, filename);
}
//some code to get data for output
return 0;
}
//function to get user data from file
//#param v(vector<int>&) - vector of integers.
//#param numToFind(int&) - the number we are looking for
//#param filename(string) - the filename of the file with data
//#return message(string) - a message containing errors or success.
string getUserDataFromFile(vector<int>& v, int& numToFind, string filename)
{
string message = "File Accepted";
string line = "";
int numOfElements = 0;
int count = 0;
ifstream fileToRead(filename.c_str());
//using 'cin >>' in main, the program runs till here then breaks
//if message is a file, extract message from file
if (fileToRead.is_open())
{
while (getline(fileToRead,line))
{
//code to do stuff with file contents here
}
fileToRead.close();
}
else
{
message = "Unable to open file.";
}
return message;
}
I left a couple of comments in the trouble areas and left out most of the code that i haven't had trouble with or haven't been able to test. Any help is appreciated. Thanks!
So my first issue was fixed by the addition of cin.ignore(INT_MAX, '\n'); any guesses on the next problem? its the line if (fileToRead.is_open()) in the next function
Add
cin.ignore();
before:
getline(cin, filename);
Otherwise, ENTER you typed after entering useFile will be read into filename.

How to pass a file into a function?

i am having difficulty understanding how to pass a file into a function.
i have a file with 20 names and 20 test scores that needs to be read by a function. the function will then assign the names and scores to a structure called student.
my question is how would i write a function call with the appropriate parameters. ? to make my function read the data in the file. thanks.
CODE
// ask user for student file
cout << "Enter the name of the file for the student data to be read for input" << endl;
cout << " (Note: The file and path cannot contain spaces)" << endl;
cout << endl;
cin >> inFileName;
inFile.open(inFileName);
cout << endl;
// FUNCTION CALL how do i set this up properly?
ReadStudentData(inFile, student, numStudents );
void ReadStudentData(ifstream& infile, StudentType student[], int& numStudents)
{
int index = 0;
string lastName, firstName;
int testScore;
while ((index < numStudents) &&
(infile >> lastName >> firstName >> testScore))
{
if (testScore >= 0 && testScore <= 100)
{
student[index].studentName = lastName + ", " + firstName;
student[index].testScore = testScore;
index++;
}
}
numStudents = index;
}
The way you pass an ifstream into the function is perfectly fine.
I suspect that the problem lies in the way you are managing your array of StudentType and its size (numStudents). I would recommend changing your code to use an std::vector instead of a raw array. In general, you should always prefer vectors over arrays unless you have a really good reason to use an array.
vectors can grow to accommodate more data and keep track of their size, so you don't have to.
Also, it's a good idea for functions to return objects rather than modify objects passed through the parameter list.
#include <vector>
using namespace std;
vector<StudentType> ReadStudentData(ifstream& infile) {
vector<StudentType> students;
string lastName, firstName;
int testScore;
while (infile >> lastName >> firstName >> testScore) {
if (testScore >= 0 && testScore <= 100) {
StudentType student;
student.studentName = lastName + ", " + firstName;
student.testScore = testScore;
students.push_back(student);
}
}
return students;
}
// call the function
vector<StudentType> students = ReadStudentData(infile);
// or if you have a C++11 compiler
auto students = ReadStudentData(infile);
// use students.size() to determine how many students were read
The reference to the file object seems to be fine, but the array of StudentType objects maybe wrong.
Try this:
void ReadStudentData(ifstream& infile,
std::vector<StudentType>& vecStudents,
int& numStudents)