filling an array of structs from a file - c++

I am trying to fill an array of structs from a given file but it doesn't seem to read anything.
/******************************************************************
* READ FILE
* This function opens the given file name and saves the info
* into an array.
******************************************************************/
int readFile(const std::string dataFile, AccessRecord accessRecordArray[], int &cou\
nt)
{
std::ifstream fin(dataFile.c_str());
if (fin.fail())
return -1;
std::string file;
while (!fin.eof())
{
fin >> file;
count++;
}
std::cout << count << std::endl;
for (int i = 0; i < count; i++)
{
fin >> accessRecordArray[i].fileName;
fin >> accessRecordArray[i].userName;
fin >> accessRecordArray[i].timeStamp;
}
fin.close();
return 0;
}
All this outputs is zero equal to the variable count. Can you help me see what I am missing?

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

Read access violation, error code 0xFFFFFFFFFFFFFFFF

I'm sorry this is a repeat question, but no solutions seem to work for my code.
This is for an assignment in school on reading from a file and copying the data to an array. An exception is thrown every time I try to edit the array "arr" in main.
Here's my code:
#include <iostream>
#include <fstream>
using namespace std;
struct Student {
string name;
float gpa;
int id;
};
void PrintStudents(Student arr[], int nstudents) {
for (int i = 0; i < nstudents; i++) {
cout << "Student name: " << arr[i].name << endl;
cout << "Student GPA: " << arr[i].gpa << endl;
cout << "Student ID: " << arr[i].id << endl;
}
}
int ReadStudents(string fname, Student arr[]) {
ifstream file;
file.open(fname);
int counter = 0;
string name_local;
float gpa_local;
int id_local;
int index = 0;
while (!file.eof()) {
if (counter == 0) {
file >> name_local;
}
else if (counter == 1) {
file >> gpa_local;
}
else if (counter == 2) {
file >> id_local;
}
counter++;
if (counter == 3) {
counter = 0;
Student newStudent = { name_local, gpa_local, id_local };
arr[index] = newStudent;
index++;
}
}
file.close();
return index;
}
void fillStudentArray(Student array[], int array_size) {
Student temp = { "", 0, 0 };
for (int i = 0; i < array_size; i++) {
array[i] = temp;
}
return;
}
int main() {
Student arr[128];
fillStudentArray(arr, 128); // exception thrown here??
cout << "Array filled." << endl;
cout << "Reading students" << endl;
int nstudents = ReadStudents("csci10.hw8.students.txt", arr);
PrintStudents(arr, nstudents);
return 0;
}
Thanks for any help! I'm totally stumped.
Edit: Woah, I left for a 30 minute coffee break and came back to a ton of answers! I'll try to respond to all of them.
Edit 2: Just got a solution! I was working in VS 2019, switched to old school terminal G++ and it worked! Thanks everyone for all the answers :)
You do not check the file was successfully opened. Try this:
ifstream file( fname );
if ( !file )
return -1;
You do not need local variables for reading. Read directly in your array elements:
file >> arr[index].name
ReadStudents ignores the size of the passed array: you might get in trouble if you read more than the allocated size (read this again). You might use std::vector, if allowed. Alternatively, pass the size, too – the same way you did for fill.
The way you are trying to read from file is overly complicated. Try a more c++ approach:
Define an extraction operator for Student:
std::istream& operator>>( std::istream& is, Student& s )
{
return is >> s.name >> s.gpa >> s.id;
}
Use it like you would use it for reading an integer:
file >> arr[ index ]
Alternatively you could use:
is >> arr[ index ].name >> arr[ index ].gpa >> arr[ index ].id
You will get something like this:
int ReadStudents( string fname, Student arr[]/*how large is the array?*/ )
{
ifstream file( fname );
if ( !file )
return -1;
int index = 0;
while ( file >> arr[ index ].name >> arr[ index ].gpa >> arr[ index ].id )
index++;
return index;
}
Explanation
If the stream does not get opened successfull, you get an endless loop. You never check if the reading operations are successfull. If they are not you never reach eof but keep incrementing index and write to array indices out of bounds. Also the counter is superfluos here.
Furthermore I would suggest to use a std::vector instead of an array and use push_back(). This makes sure, you don't write out of bounds.
(Possible) solution
This loop:
while (!file.eof()) {
if (counter == 0) {
file >> name_local;
}
else if (counter == 1) {
file >> gpa_local;
}
else if (counter == 2) {
file >> id_local;
}
counter++;
if (counter == 3) {
counter = 0;
Student newStudent = { name_local, gpa_local, id_local };
arr[index] = newStudent;
index++;
}
}
should be changed (with the function definition) to:
int ReadStudents(string fname, std::vector<Student> &vec)
{
// open stream, etc.
while (file >> name_local >> gpa_local >> id_local) {
Student newStudent = { name_local, gpa_local, id_local };
vec.push_back(newStudent);
}
// cleanup
}
To explain a bit further what the while (file >> name_local >> gpa_local >> id_local) does:
Since std::ifstream::operator>> returns a reference to the stream itself, you can chain those statements together.
The last reference gets implicitly converted to bool (or void* in c++11 or earlier) as seen here. This evaluates true if the last reading operations where successfull (so name_local, gpa_local and id_local now have valid values) and the stream is ready for IO-operations (so it didn't reach eof while reading). This implies that it's also checking if the stream was opened at all.
Once those conditions are met you can create a new element and push it into the vector.

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.

Input from txt file doesn't match when it is read/passed second time (C++)

So I am fairly new to coding and c++. So...sorry if this is something very obvious to some of you:
I am having a hard time getting this code to read the input stored in txt file for a second time. It works for the first time.
void readcode(ifstream& infile, int list[], int& length, bool& lenCodeOk)
{
int count;
lenCodeOk = true;
infile >> length; //get the length of the secret code
cout << "Length1 is "<<length<<endl;
if (length > MAX_CODE_SIZE)
{
lenCodeOk = false;
return;
}
//Get the secret code.
for (count = 0; count < length; count++)
{
infile >> list[count];
}
cout<<" Code recorded is: ";
for (count = 0; count < length; count++)
{
cout<<list[count]<<" "<<endl;
}
}
So the first integer in my txt file is the length of the sequence of integers. This function does everything it is supposed to. Reads the length correctly also stores everything in an array.
However when I call the below compareCode function after calling the readcode function, it comes out with a completely random/different length2 (that changes/goes one up everytime I call) and array elements.
void compareCode(ifstream& infile, ofstream& outfile, const int list[], int length)
{
int length2;
int digit;
bool codeOk;
int count;
codeOk = true;
infile >> length2;
cout<<"Length2 is "<<length<<endl;
if(length != length)
{
cout<< "The original code and its copy are not of the same length"<<endl;
return;
}
outfile << "Code Digit Code Digit Copy"<<endl;
for (count= 0; count<length; count++)
{
infile >> digit;
outfile<<setw(5)<<list[count]<<setw(17)<<digit;
if (digit != list[count])
{
outfile << " Code digits are not the same"<<endl;
codeOk = false;
}
else
{
outfile<<endl;
}
if (codeOk)
{
outfile<<"Message transmitted OK."<<endl;
}
else
{
outfile<<"Error in transmission. "<<"Retransmit!!"<<endl;
}
}
}
It seems like I am missing an important piece of information about passing fstream variables I would really appreciate if someone pointed me towards the right direction.
int main()
{
int codeArray[MAX_CODE_SIZE];//Array to store the secret code
int codeLength;// Variable to store the length of the code
int codeLength2;
bool lengthCodeOk;//Variable to indicate if the legth of the secret code is less than or equal to 250
ifstream incode;// Declare ifstream variable
ofstream outcode;//Declare ofstream variable
char inputFile[51];//Variable to store the name of the input file
char outputFile[51]; //Variable to store the name of the output file
cout<<"Enter the input file name: "<<endl;
cin>> inputFile;//makesure it is one word because ci.>>skips white space
cout<<endl;
incode.open(inputFile);
if(!incode)
{
cout<< "Cannot open the input file."<<endl;
return 1;
}
cout<< "Enter the output file name: " ;
cin>> outputFile;//Same deal, one word so cin>> can read
cout<<endl;
outcode.open(outputFile);
readcode(incode,codeArray,codeLength,lengthCodeOk);
if (lengthCodeOk)
{
compareCode(incode,outcode,codeArray,codeLength);
}
else
{
cout<<"Length of the secret code must be <= "<<MAX_CODE_SIZE<<endl;
}
incode.close();
outcode.close();
return 0;
}
this should go like this:
istream& readcode(istream& infile, std::vector<int>& list)
{
int length;
if (infile >> length) {
list.reserve(length);
for (int count = 0; count < length; count++)
{
int x;
if (infile >> x)
{
list.push_back(x);
} else {
break;
}
}
}
return infile;
}
ifstream file("somefile.txt");
if (file.good())
{
std::vector<int> a, b;
if (readcode(file, a).good())
{
file.seekg(0);
if (readcode(file, b).good())
{
cout << (a!=b? "code reading are different" : "code reading are same") << endl;
}
else
{
cerr << "failed read again code" << endl;
}
}
else
{
cerr << "failed read code" << endl;
}
}

Avoiding the use of eof in this case

I have posted the following code where I am reading from an input file -- storing information in a structure -- and then writing to an output file. I know that the eof function is not safe and hence one must use the getline function to check whether the end of file has been detected or not; however, in this particular code, I have not been able to use the getline function and hence has finally relied on the eof function. Hence, can you please suggest an alternative to the eof function or let me know how I can use the getline function when I am trying to initialize an array of structures . I have used two asterisk symbols to indicate where I want to use the getline function.
#include <iostream>
#include <fstream>
using namespace std;
//student structure
struct student
{
char name[30];
char course[15];
int age;
float GPA;
};
ifstream inFile;
ofstream outFile;
student getData();
void writeData(student writeStudent);
void openFile();
int main (void)
{
const int noOfStudents = 3; // Total no of students
openFile(); // opening input and output files
student students[noOfStudents]; // array of students
// Reading the data from the file and populating the array
for(int i = 0; i < noOfStudents; i++)
{
if (!inFile.eof()) // ** This where I am trying to use a getline function.
students[i] = getData();
else
break ;
}
for(int i = 0; i < noOfStudents; i++)
writeData(students[i]);
// Closing the input and output files
inFile.close ( ) ;
outFile.close ( ) ;
}
void openFile()
{
inFile.open("input.txt", ios::in);
inFile.seekg(0L, ios::beg);
outFile.open("output.txt", ios::out | ios::app);
outFile.seekp(0L, ios::end);
if(!inFile || !outFile)
{
cout << "Error in opening the file" << endl;
exit(1);
}
}
student getData()
{
student tempStudent;
// temp variables for reading the data from file
char tempAge[2];
char tempGPA[5];
// Reading a line from the file and assigning to the variables
inFile.getline(tempStudent.name, '\n');
inFile.getline(tempStudent.course, '\n');
inFile.getline(tempAge, '\n');
tempStudent.age = atoi(tempAge);
inFile.getline(tempGPA, '\n');
tempStudent.GPA = atof(tempGPA);
// Returning the tempStudent structure
return tempStudent;
}
void writeData(student writeStudent)
{
outFile << writeStudent.name << endl;
outFile << writeStudent.course << endl;
outFile << writeStudent.age << endl;
outFile << writeStudent.GPA << endl;
}
You want to write an operator>> for your student type. Something like:
std::istream& operator>>(std::istream& in, student& s) {
in >> s.age; // etc.
return in;
}
Which then allows you to write:
int studentNo = 0;
students[maxStudents];
while (studentNo < maxStudents && (in >> students[studentNo]))
++studentNo;
Why not write this way?
instead of
inFile.getline(tempStudent.name, '\n');
inFile.getline(tempStudent.course, '\n');
inFile.getline(tempAge, '\n');
You may
while(inFile.getline(tempStudent.name, '\n'))
{
inFile.getline(tempStudent.course, '\n');
inFile.getline(tempAge, '\n');
//do stuffs
}