【问题标题】:Output file overwriting incorrectly输出文件覆盖不正确
【发布时间】:2014-06-07 20:08:56
【问题描述】:

这只是与my last question一起使用,有人要求我上传文件,所以我将删除所有无用的功能并保留主要代码,尤其是与输出有关的代码,这是我的第三个问题堆栈溢出,所以我仍然不太了解它是如何工作的,如果您想回答,请查看my last (2nd) question 了解详细信息。代码如下:

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

【问题讨论】:

  • 首先,您可以告诉我们您遇到的具体错误/错误行为
  • TL;博士!请将代码缩小到您遇到问题的部分,或者(甚至更好!)创建一个Minimal, Complete, and Verifiable example 并向我们展示。
  • 这里解释了错误:stackoverflow.com/questions/23236093/… 在我的最后一个问题中。这是帮助解决此问题的代码。
  • 如果您正在寻求帮助,明智的策略是尽可能轻松地帮助您。是的,这意味着写几行甚至几段,而不是期望我们搜索您以前的问题,甚至关注链接......此外,准备 SSCCE 是一个很好的帮助(很多时候我的问题自己“独自”解决了,而这样做)

标签: c++ output overwrite


【解决方案1】:

这里

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&gt;&gt;):

std::vector<Student> roster;

//...

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

【讨论】:

  • 在更改后的循环中,您可能应该重新排列条件,以便首先检查 numStuds &lt; MAX_SIZE
  • 哈哈,非常感谢!几个小时以来,我一直在搞乱它与 outFile 一起工作的部分,可能永远不会想到这一点:/
  • 此外,如果 OP 更改为使用 std::vector,那么您可以将 std::copystd::istream_iteratorstd::back_inserter 一起使用,而不是最后一个循环。
  • @JoachimPileborg 添加。
猜你喜欢
  • 2016-11-19
  • 2016-06-04
  • 2013-01-25
  • 1970-01-01
  • 2018-04-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-03-10
相关资源
最近更新 更多