SN-Lab10.cc
// Dr. Norman's Solution to ENGG 233 Fall 2004 Lab 10
//
// Note that there will be another solution posted on Blackboard.
// Both solutions will do essentially the same things, but there may
// be some minor differences due to differences in interpretation of
// the Lab 10 instructions.
// GENERAL REMARKS:
//
// (1) This program does not check for user input errors, such as
// mistakes typing in info for a new student. It also doesn't
// check for incorrectly formatted input files. These checks
// would make the program safer for use, but would also require
// a lot more code.
//
// (2) The program is terminated after a few failed attempts to open
// the input file. An alternate strategy would be to let the program
// continue with an initially empty vector of students, which would be
// let the user try to create a new data file by adding some new students
// to the vector.
//
// (3) It is assumed that students don't have multi-word last names
// or first names with spaces in them.
//
// (4) The lab instructions don't say what to do with the
// final_score and letter_grade members when the file input is done
// or when a new student is added. I chose to give these members
// specific values (-1.0 and 'X') that could not be mistaken for
// properly calculated values. When FindStudent is displaying info
// about a student, it checks to see whether the letter grade and
// final score have been calculated.
//
// (5) If two or more students have the same last name, FindStudent
// just finds the one that is first in the list. This would be bad
// in a program given to real users!
#include <iostream>
#include <vector>
#include <string>
#include <cstdlib>
#include <fstream>
using namespace std;
struct student
{
string last;
string first;
int id;
double midterm;
double final;
vector<double> lab_scores;
double final_score;
char letter_grade;
};
// Size of lab_scores vector.
const int NUMBER_OF_LABS = 5;
// How many tries should the user have to pick a valid file name?
const int MAX_OPEN_ATTEMPTS = 3;
// Values for final_score and letter_grade to indicate "not calculated yet".
const double INITIAL_FINAL_SCORE = -1.0;
const char INITIAL_LETTER_GRADE = 'X';
// Weights for components in a student's final score, and minimum scores
// for letter grades.
const double LAB_WEIGHT = 0.2;
const double MIDTERM_WEIGHT = 0.3;
const double FINAL_WEIGHT = 0.5;
const double MINIMUM_A_SCORE = 80.0;
const double MINIMUM_B_SCORE = 70.0;
const double MINIMUM_C_SCORE = 60.0;
const double MINIMUM_D_SCORE = 50.0;
void ReadData(vector <student> & section, int& num_Students,string& filename);
void WriteData(const vector <student> & section,
int num_Students,
const string& filename);
void AddNewStudent (vector <student> & section, int& num_Students);
void CalculateScore (vector <student> & section);
void FindStudent (const vector <student> & section);
int main()
{
// This code is the same as what was given to students, except that
// indentation and line breaks have been modified to make the code
// look better in an editor window.
vector<student> section;
int num_Students=0;
string filename;
ReadData(section, num_Students, filename);
char choice;
do {
cout << "What do you wish to do with the database?"<<endl;
cout << "Input the relevant letter: Options are"<<endl;
cout << "(A) Add new student" <<endl;
cout << "(B) Calculate the final score and letter grade for the students"
<<endl;
cout<<"(C) Find a student and output their details"<<endl;
cout<<"(D) End the program"<<endl;
cin>>choice;
switch (choice) {
case ('A'):
AddNewStudent(section, num_Students);
break;
case ('B'):
CalculateScore(section);
break;
case ('C'):
FindStudent(section);
break;
case ('D'):
cout << "program ending" << endl;
WriteData(section, num_Students, filename);
}
} while(choice != 'D');
return 0;
}
void ReadData(vector<student> & section, int& num_Students, string& filename)
{
// Attempt to get a file name and open the file.
ifstream in;
cout << "Please enter the name of a file containing grade data: " << endl;
cin >> filename;
in.open(filename.c_str());
// If the file did not get opened, give the user more chances to
// pick a valid file name.
int open_count = 1; // So far, 1 try at opening the file.
while (in.fail() && open_count < MAX_OPEN_ATTEMPTS) {
cout << "Failed to open " << filename
<< "; please try another file name: " << endl;
cin >> filename;
in.clear();
in.open(filename.c_str());
open_count++;
}
if (in.fail()) {
cout << "Program is quitting due to "
<< "repeated failures to open the input file." << endl;
exit(1);
}
// Read all the data from the file into section, and assign safe values
// to final score_and letter_grade members. Then close the file.
in >> num_Students;
section.resize(num_Students);
for (int i = 0; i < num_Students; i++) {
in >> section.at(i).first;
in >> section.at(i).last;
in >> section.at(i).id;
in >> section.at(i).midterm;
in >> section.at(i).final;
section.at(i).lab_scores.resize(NUMBER_OF_LABS);
for (int lab = 0; lab < NUMBER_OF_LABS; lab++)
in >> section.at(i).lab_scores.at(lab);
section.at(i).final_score = INITIAL_FINAL_SCORE;
section.at(i).letter_grade = INITIAL_LETTER_GRADE;
}
in.close();
}
void WriteData(const vector<student> & section,
int num_Students,
const string& filename)
{
// Try to open the file, then check for failure.
ofstream ofs;
ofs.open((filename).c_str());
if (ofs.fail()) {
cout << "WARNING: Not able to save data to " << filename << endl;
return;
}
// Write the data and close the file.
ofs << num_Students << '\n';
for (int i = 0; i < num_Students; i++) {
ofs << section.at(i).first;
ofs << ' ' << section.at(i).last;
ofs << ' ' << section.at(i).id;
ofs << ' ' << section.at(i).midterm;
ofs << ' ' << section.at(i).final;
for (int lab = 0; lab < NUMBER_OF_LABS; lab++)
ofs << ' ' << section.at(i).lab_scores.at(lab);
ofs << '\n';
}
ofs.close();
}
void AddNewStudent (vector<student> & section, int& num_Students)
{
// No checks for input failure! If the user makes a typing mistake
// the program will be in serious trouble.
student new_student;
cout << "Please enter new student's first name: " ;
cin >> new_student.first;
cout << "Please enter last name: " ;
cin >> new_student.last;
cout << "Please enter ID number: " ;
cin >> new_student.id;
cout << "Please enter midterm mark: " ;
cin >> new_student.midterm;
cout << "Please enter final exam mark: " ;
cin >> new_student.final;
cout << "Please enter " << NUMBER_OF_LABS
<< " lab marks, separated by spaces:\n";
new_student.lab_scores.resize(NUMBER_OF_LABS);
for (int lab = 0; lab < NUMBER_OF_LABS; lab++)
cin >> new_student.lab_scores.at(lab);
new_student.final_score = INITIAL_FINAL_SCORE;
new_student.letter_grade = INITIAL_LETTER_GRADE;
section.push_back(new_student);
num_Students++;
}
void CalculateScore (vector<student> & section)
{
// This is a straightforward application of the rules given in the
// Lab 10 instructions.
for (int i = 0; i < section.size(); i++) {
double course_total, lab_total = 0;
course_total = FINAL_WEIGHT * section.at(i).final;
course_total += MIDTERM_WEIGHT * section.at(i).midterm;
for (int lab = 0; lab < NUMBER_OF_LABS; lab++)
lab_total += section.at(i).lab_scores.at(lab);
course_total += LAB_WEIGHT * lab_total;
section.at(i).final_score = course_total;
if (course_total >= MINIMUM_A_SCORE)
section.at(i).letter_grade = 'A';
else if (course_total >= MINIMUM_B_SCORE)
section.at(i).letter_grade = 'B';
else if (course_total >= MINIMUM_C_SCORE)
section.at(i).letter_grade = 'C';
else if (course_total >= MINIMUM_D_SCORE)
section.at(i).letter_grade = 'D';
else
section.at(i).letter_grade = 'F';
}
}
void FindStudent (const vector<student> & section)
{
// Show all last names to user, then ask for a last name as input.
cout << "Last names of students are:\n";
for (int i = 0; i < section.size(); i++)
cout << " " << section.at(i).last << endl;
string name_to_find;
cout << "Please enter the last name of a student: ";
cin >> name_to_find;
// Search for first appearance of the last name in section. (This
// should be FIXED to handle the possibility that two students have
// the same last name.)
int i_of_name = 0;
while (i_of_name < section.size()
&& name_to_find != section.at(i_of_name).last)
i_of_name++;
// If a match was found, display information for that student.
if (i_of_name == section.size())
cout << "Sorry, last name " << name_to_find
<< " is not in the list." << endl;
else {
cout << "\nFull name: " << section.at(i_of_name).first
<< ' ' << section.at(i_of_name).last << endl;
if (section.at(i_of_name).letter_grade == INITIAL_LETTER_GRADE)
cout << "Final score and letter grade not yet calculated.\n\n";
else
cout << "Final score: " << section.at(i_of_name).final_score
<< ". Letter grade: " << section.at(i_of_name).letter_grade
<< ".\n\n";
}
}
Generated by GNU enscript 1.6.1.