Question

This is just to go with my last question, someone asked me to upload the file so I'll cut out all the useless functions and have the main code especially that having to do with the output, this is my 3rd question on stack overflow so I still don't know much about how it works, if you want to answer please check my last (2nd) question for details. Here is the code:

#include <iostream>
#include <iomanip>
#include <fstream>

using namespace std;

const int MAX_SIZE = 1000;

struct Student
{
string studentID;
string firstName;
char midInitial;
string lastName;
};


void menu()
{
   cout<<"         CLASS ROSTER APPLICATION"<<endl;
   cout<<"========================================="<<endl;
   cout<<"ADD a student record..................[A]"<<endl;
   cout<<"DELETE a student......................[D]"<<endl;
   cout<<"EDIT a student record.................[E]"<<endl;
   cout<<"INQUIRY about a student...............[I]"<<endl;
   cout<<"LIST all students.....................[L]"<<endl;
   cout<<"QUIT the system.......................[Q]"<<endl;
}


int linearSearch(const Student roster[], int numStuds, string sID)
{
   int i;
   for (i=0; i<numStuds; i++)
   {
       if (roster[i].studentID == sID)
          return i;
   }
   return -1;
}


void selSort(Student roster[], int numStuds)
{
int minIDPos;
Student tempStudRecord;
int i,j;
for (i=0; i<numStuds-1; i++)
{
    minIDPos = i;
    for (j=i+1; j<numStuds; j++)
    {
        if (roster[j].studentID < roster[minIDPos].studentID)
            minIDPos = j;
    }
    tempStudRecord = roster[i];
    roster[i] = roster[minIDPos];
    roster[minIDPos] = tempStudRecord;
 }
}


void listStudents(const Student roster[], int numStuds)
{
 cout<<"C L A S S  R O S T E R"<<endl;
cout<<"Student ID #  First Name   M.I.  Last Name"<<endl;
cout<<"---------------------------------------------"<<endl;
 int i2=0;  //just a counter.
 while (i2<numStuds)
 {
    cout<<left;
    cout<<setw(14)<<roster[i2].studentID<<setw(13)<<roster[i2].firstName;
    cout<<roster[i2].midInitial<<".    "<<roster[i2].lastName;
    cout<<endl;
    i2++;
 }
 cout<<right;
  cout<<"---------------------------------------------"<<endl;
cout<<"Enrollment: "<<i2<<endl;

}

int main()
{
Student roster[MAX_SIZE];
fstream inFile;
fstream outFile;
string filename, sID;
Student newStudent;
int numStuds = 0;
char choice;
int i;
cout<<"Enter the name of the data file> ";
cin>>filename;
/** 7. open the data file for input **/
inFile.open(filename.c_str(), ios::in);

if (inFile)
{
    /** 8. write a while loop to read the data from the file
     into the roster array; the numStuds (number of Students)
     must be updated as the records are read from the file.

     Also, close the file after its contents are read into the
     roster array.
     **/
    while (!inFile.eof() && numStuds < MAX_SIZE)
    {
        inFile>>roster[numStuds].studentID>>roster[numStuds].firstName;
        inFile>>roster[numStuds].midInitial>>roster[numStuds].lastName;
        numStuds++;
    }
    inFile.close();
}
do
{
    cout<<endl;
    menu();
    cout<<endl;
    cout<<"Select an option-> ";
    cin>>choice;
    cout<<endl;
    switch(toupper(choice))
    {
        case 'A': cout<<"Enter the student ID #> ";
            cin>>newStudent.studentID;
            cout<<"Enter the student's first name> ";
            cin>>newStudent.firstName;
            cout<<"Enter the student's middle initial> ";
            cin>>newStudent.midInitial;
            cout<<"Enter the student's last name> ";
            cin>>newStudent.lastName;
            addStudent(roster,numStuds,newStudent);
            break;

        case 'D': /** 9. write code here to remove a student from the roster **/
            cout<<"Enter the student ID Number: ";
            cin>>sID;
            deleteStudent(roster, numStuds, sID);
            break;

        case 'E': /** 10. write code to edit the record for a student with a specified ID # **/
            cout<<"Enter the student ID Number: ";
            cin>>sID;
            editStudent(roster, numStuds, sID);
            break;

        case 'I': /** 11. write code to perform an inquiry (obtain full name) on a student with
                   with a specified ID # **/
            cout<<"Enter the student ID Number: ";
            cin>>sID;
            studentInquiry(roster, numStuds, sID);
            break;

        case 'L': /** 12. write code to sort and then generate class roster **/
            selSort(roster, numStuds);
            listStudents(roster, numStuds);
            break;

        case 'Q': break;

        default:  cout<<"Invalid menu choice...try again!"<<endl;
    }
}while(toupper(choice) != 'Q');

/** 13. open the data file in output mode and error-check to ensure
 that it was successfully opened.
 **/
outFile.open(filename.c_str(), ios::out);
    if (!outFile)
    {
            cout<<"Unable to open "<<filename<<" for output. "<<endl;
            return -1;
    }


/** 14. overwrite the data file in the order:
 student ID, firstname, middle initial and last name, one record per line.
 make sure that you have spaces between the fields.
 **/           
for (i=0;i<numStuds;i++)   
{
    outFile<<roster[i].studentID<<" "<<roster[i].firstName<<" ";
    outFile<<roster[i].midInitial<<" "<<roster[i].lastName<<endl;
} 


/** 15. close the output file **/
outFile.close();

return 0;
}
Was it helpful?

Solution

This here

while (!inFile.eof() && numStuds < MAX_SIZE) {
  inFile >> roster[numStuds].studentID >> roster[numStuds].firstName;
  inFile >> roster[numStuds].midInitial >> roster[numStuds].lastName;
  numStuds++;
}

Will leave the value of numStuds one higher than it should be, as inFile.eof() will only return true once the end of file has been reached, which won't occur until you have actually tried to read past the end of the file.

One way of fixing it would be to change it to

while (numStuds < MAX_SIZE &&
  (inFile >> roster[numStuds].studentID >> roster[numStuds].firstName >>
  roster[numStuds].midInitial >> roster[numStuds].lastName)
) {
  numStuds++;
}

Although you're better off defining a function that reads the struct for you

std::istream& operator>>(std::istream& stream, Student& student)
{
  stream >> student.studentID >> student.firstName
         >> student.midInitial >> student.lastName;
  return stream;
} 

Which will work as follows:

while (inFile >> roster[numStuds]) {
  numStuds++;
}

As suggested by @JoachimPileborg the following would be even better (once operator>> is defined for your struct):

std::vector<Student> roster;

//...

std::copy(
  std::istream_iterator<Student>(inFile),
  std::istream_iterator<Student>(),
  std::back_inserter(roster)
);
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top