Need help to store the record of the current student in the students array
Solution 1:
You should use the C++ goodies, and learn to be more conservative with the idioms.
main
should be int main()
or int main(int argc, char *argv[])
. On some environments you can also use int main(int argc, char *argv[], char **environ)
but never use the ugly void main()
. Despite being equivalent in C++ int main(void)
will only unsettle future readers.
In C++ a class (or a struct because it is the same thing) can contain methods. Instead of building a free function using a single argument that is an instance of a class it is generally better to make a method from it.
When you detect an error condition and write a fatal error message, you should not continue the program flow.
The injectors (resp. extractors) can be used to directly extract (resp. write) an object from (rest. into) a stream. It generally gives a more idiomatic code.
As you said that Student students[24]
was provided I kept it, but in fact a single Student could be because you could print at read time. Here I have separated the reading of the records from the prints.
SO here is a possible code:
#include <iostream>
#include <string>
#include <fstream>
// avoid using namespace std because it really import too many symbols
using std::string;
using std::ifstream;
using std::istream;
using std::cerr;
using std::cout;
using std::endl;
/* structure */
struct Student {
string name;
double midTerm;
double finalExam;
double lab[4]; // making lab an array allows iterating on it
// you can directly "cache" the computed values in the object itself
double grade;
string letterGrade;
/* function prototype - better to make it a method */
void calculateGrade();
};
// an extractor for the Student class
istream& operator >> (istream& in, Student& student) {
if (!std::getline(in, student.name)) return in; // immediately give up on eof
in >> student.midTerm >> student.finalExam;
for (double& lab : student.lab) {
in >> lab;
}
if (in) {
student.calculateGrade();
// skip the end of last line because we want to use getline...
if (in.ignore().eof()) { // but do not choke on end of file
in.clear();
}
}
return in;
}
/* main function */
int
main()
{
Student newStudent;
Student students[24];
ifstream inFile;
unsigned nStudents = 0;
inFile.open("students.txt");
if (!inFile) {
cerr << "Unable to open file.\n";
return EXIT_FAILURE;
}
// C++ allows to directly iterate any container including a plain array
for (Student& student : students) {
inFile >> student; // as we iterate through references we can change the object
if (inFile) {
nStudents++;
}
else { // give up on error or eof
if (!inFile.eof()) { // but only write a message on error
cerr << "Error reading file.\n";
}
break;
}
}
// time to display the results
for (int i = 0; i < nStudents; i++) {
cout << students[i].name << "'s final grade is " << students[i].grade
<< "% (grade: " << students[i].letterGrade << ")" << endl;
}
exit(EXIT_SUCCESS);
}
// the method implementation
void
Student::calculateGrade()
{
double exams, labs;
exams = 0.25 * (midTerm) + 0.25 * (finalExam);
labs = 0.125 * (lab[0] + lab[1] + lab[2] + lab[3]);
grade = (exams + labs);
if (grade >= 90.0)
letterGrade = 'A';
else if (grade <= 89.9 && grade >= 80.0)
letterGrade = 'B';
else if (grade <= 79.9 && grade >= 70.0)
letterGrade = 'C';
else if (grade <= 69.9 && grade >= 60.0)
letterGrade = 'D';
else
letterGrade = 'F';
}