输出文件覆盖不正确

Output file overwriting incorrectly

本文关键字:不正确 覆盖 文件 输出      更新时间:2023-10-16

这只是我的最后一个问题,有人让我上传文件,这样我就可以去掉所有无用的函数,并获得主代码,尤其是与输出有关的代码,这是我关于堆栈溢出的第三个问题,所以我仍然不太了解它是如何工作的,如果你想回答,请查看我的最后(第二)个问题以了解详细信息。这是代码:

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

此处为

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

将使numStuds的值比它应该的值高一个,因为inFile.eof()只会在到达文件末尾时返回true,直到您真正尝试读取超过文件末尾时才会发生这种情况。

修复它的一种方法是将其更改为

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

尽管您最好定义一个函数来为读取结构

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

其工作原理如下:

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

正如@JoachimPileborg所建议的那样,以下会更好(一旦为您的结构定义了operator>>):

std::vector<Student> roster;
//...
std::copy(
  std::istream_iterator<Student>(inFile),
  std::istream_iterator<Student>(),
  std::back_inserter(roster)
);