C ++의 파일에서 개체를 읽는 동안 문제가 발생했습니다.

Nov 28 2020

저는 OOP 개념을 사용하여 파일에서 레코드를 추가, 편집 및 검색해야하는 소규모 대학 프로젝트를 수행하고 있습니다. 파일에 추가하는 것은 잘 작동하지만 파일에서 읽으려고 할 때마다 읽을 수없는 텍스트로 인쇄됩니다. 다음은 전체 코드와 출력입니다. main.cpp

#include <iostream>
#include <cstdlib>
#include <fstream>
#define MIN 20
#define MAX 100
#include "student.h"

using namespace std;

void add_student();
void edit_student();
void search_student();
void addToFile(const Student&);
Student* fetchFromFile();
int getFileSize();
void updateFile(Student*);

// Student stud[MAX];
int main()
{
  int choice;
  system("cls");                                                  
  system("Color B0");
  while(1)
  {                                                                                            
    cout<<"\n\t\tWhat do you want to do?"<<endl;
    cout<<"\t\t----------------------"<<endl;                                                 
    cout<<"\t\t1-Add student"<<endl;                                                       
    cout<<"\t\t2-Edit student"<<endl;                                                         
    cout<<"\t\t3-Search student"<<endl;                                                   
    cout<<"\t\t4-Quit Program"<<endl;                                                              
    cout<<"\t\t----------------------"<<endl;            
    cout<<"Enter your choice: ";                           
    cin>>choice;                                           
    switch(choice)                                         
    {
      case 1:
        add_student(); //calling add_student function to add records.
        break;
      case 2:
        edit_student();
        break;
      case 3:
        search_student();
        break;
      case 4:
        return 0;
        break;
      default:
        cout<<"Invalid choice";
        break;
    }
}
  return 0;
}

int Student::id = getFileSize() - 1; //Initialize id equals to size of file

// setData function of class Student definition
void Student :: setData()
{
  // taking input from user
  cout<<"Enter student roll no in format(1XXX): ";
  cin>>roll;
  cout<<"Enter student name: ";
  cin>>name;
  cout<<"Enter stduent date of birth(dd/mm/yy): ";
  cin>>dob;
  cout<<"Enter stduent phone no: ";
  cin>>phone;
  cout<<"Enter student address: ";
  cin>>address;
  stdId = Student::id;
}

void Student :: showData()
{
  cout<<stdId<<"  ";
  cout<<roll<<"   ";
  cout<<name<<"     ";
  cout<<dob<<"\t";
  cout<<phone<<"   ";
  cout<<address<<"\n\n";
}

const int Student :: getRoll()
{
  return roll;
}

Student& Student::operator = (const Student& newObj)
{
  stdId = newObj.stdId;
  roll = newObj.roll;
  name = newObj.name;
  dob = newObj.dob;
  phone = newObj.phone;
  address = newObj.address;
  return *this;
}

void add_student()
{
  Student stud;
  Student::incrementId();
  stud.setData();
  addToFile(stud); //adding records to file
  system("CLS");
  cout<<endl;
  cout<<"--------------------------------------------------------------------------------"<<endl;
  cout<<"---------------------------Student updated record Table---------------------------------"<<endl;
  cout<<"--------------------------------------------------------------------------------"<<endl;
  cout<<"ID      "<<"Roll      "<<"Name      "<<"DOB      "<<"Phone no         "<<"Address\n\n";
  cout<<"--------------------------------------------------------------------------------"<<endl;

  Student* student = fetchFromFile(); //getting records from file in array of objects
  int length = getFileSize(); //getting length of array of objects

  for(int i=0; i<(length-1); i++)
  {
    student[i].showData(); //showing all the data
  }

  cout<<"--------------------------------------------------------------------------------"<<endl;
  cout<<"---------------------------------FINISH-----------------------------------------"<<endl;
  cout<<"--------------------------------------------------------------------------------"<<endl;
  cout<<"You want to add more?(Y/n):  ";
  char c;
  cin>>c;
  if(c=='y' || c=='Y')
  {
    add_student();
  }
  else{
    system("pause");
  }
}

void edit_student(){
  //Showing existing record first before editing
  cout<<endl;
  cout<<"--------------------------------------------------------------------------------"<<endl;
  cout<<"---------------------------Student Existing record Table---------------------------------"<<endl;
  cout<<"--------------------------------------------------------------------------------"<<endl;
  cout<<"ID   "<<"Roll   "<<"Name      "<<"DOB      "<<"Phone no         "<<"Address\n\n";
  cout<<"--------------------------------------------------------------------------------"<<endl;

  Student* student = fetchFromFile(); //fetching all records from file
  int length = getFileSize();

  for(int i=0; i<(length-1); i++)
  {
    student[i].showData();
  }
  int idnumber;
  cout<<"--------------------------------------------------------------------------------"<<endl;
  cout<<"Which ID number your want to edit: ";

  cin>>idnumber;            //Asking the user at which ID he wants to make a change.
  //checking for valid id number
  if(idnumber>length || idnumber<0)
  {
    cout<<"\nInvalid ID Number."<<endl;
  }
  //showing existing information about that specific record
  cout<<"\nExisted information about this record.\n\n";
  cout<<"--------------------------------------------------------------------------------"<<endl;
  cout<<"ID   "<<"Roll   "<<"Name      "<<"Father\tCell no.      "<<"DOB          "<<"Address\n\n";
  cout<<"--------------------------------------------------------------------------------"<<endl;
  student[idnumber].showData();
  cout<<"\n\nEnter new data for above shown record.\n\n";
  student[idnumber].setData();         //Inputting data for that specific record.
  updateFile(student);
  cout<<"\n\nRecord updated successfully."<<endl;
  cout<<endl;
  cout<<"--------------------------------------------------------------------------------"<<endl;
  cout<<"---------------------------Updated record Table---------------------------------"<<endl;
  cout<<"--------------------------------------------------------------------------------"<<endl;
  cout<<"ID   "<<"Roll   "<<"Name      "<<"DOB      "<<"Phone no         "<<"Address\n\n";
  cout<<"--------------------------------------------------------------------------------"<<endl;
  for(int i=0; i<(length-1); i++) //Showing updated record Table
  {
    student[i].showData();
  }
}

void search_student(){
  Student* student = fetchFromFile();
  int fileLenth = getFileSize() - 1;
  int searchkey;
  cout<<"Enter roll_no of student you want to search: ";
  cin>>searchkey;     //roll_no as the search key can be entered by user.
  for(int i=1; i<fileLenth; i++)
  {
    if(searchkey==student[i].getRoll()) //checking for roll no
    {
      student[i].showData();
    }
  }
  cout<<"--------------------------------------------------------------------------------"<<endl;
  cout<<"---------------------------------FINISH-----------------------------------------"<<endl;
  cout<<"--------------------------------------------------------------------------------"<<endl;
  system("pause");
}

//FILE HANDLING

void addToFile(const Student& obj)
{
  ofstream fout;
  fout.open("records.txt", std::ofstream::app | std::ofstream::binary);
  fout.write((char*)&obj, sizeof(obj));
  cout<<"Added to file successfully!"<<endl;
  fout.close();
}

Student* fetchFromFile()
{
  int i=0;
  Student obj;
  Student* returnObj = new Student[MAX];
  ifstream fin;
  fin.open("records.txt", std::ifstream::binary);
  while(!fin.eof())
  {
    fin.read((char*)&obj, sizeof(obj));
    returnObj[i] = obj;
    i++;
  }
  fin.close();
  delete[] returnObj;
  return returnObj;
}

int getFileSize()
{
  int i=0;
  Student obj;
  ifstream fin;
  fin.open("records.txt", std::ifstream::binary);
  while(!fin.eof())
  {
    fin.read((char*)&obj, sizeof(obj));
    i++;
  }
  fin.close();
  return i;
}

void updateFile(Student* student)
{
  ofstream fout;
  fout.open("records.txt", std::ofstream::binary);
  fout.write((char*)&student, sizeof(student));
  fout.close();
}

student.h 헤더 파일

// A student class that hold students attributes like id, name, address and class
// Object of this class will be craeted to store student details
class Student
{
  int stdId;
  int roll;
  std::string name;
  std::string dob;
  std::string phone;
  std::string address;
public:
  static int id; //we will increase 'id' whenever student is added to the record
  //Member functions declaration
  void setData(); //this function will take input from user and set the data to attributes of class
  void showData(); //This function will give student data to user when called
  static void incrementId()
  {
    id++;
  }
  const int getRoll();
  Student& operator = (const Student&);
};

샘플 출력 1

파일에 학생 객체를 추가 할 때

샘플 출력 2

파일에서 모든 레코드 읽기

문제 1 : id의 가비지 값을 표시합니다.

샘플 출력 3

파일에 다른 개체 추가

샘플 출력 4

파일에서 모든 개체 읽기

샘플 출력 5

이제 돌아가서 레코드 편집을 선택했습니다.

문제 2 : 레코드가 읽을 수없는 형식으로 인쇄되는 방식을 확인하십시오.

왜 이런 일이 발생합니까? 이제 프로그램을 닫고 다시 실행하면 여전히 읽을 수없는 텍스트로 표시됩니다. 내 문제를 이해하기를 바랍니다. 이에 대한 자세한 설명이 필요합니다. 또한 다른 실수를했다면 알려주세요. 감사합니다!

답변

2 user4581301 Nov 29 2020 at 04:48

Student너무 포맷되지 않은 같은 IO와 읽기 복잡 read하고 write. 기술적 인 측면에서 s가 포함되어 있고 Trivially Copyable이 아니기 때문에 Trivially Copyable 이 아닙니다.std::stringstring

가장 쉬운 방법은 readwrite. 데이터의 대부분은 문자열 데이터, 그래서 쓰기입니다 <<>>대한 과부하 Student및 텍스트로 저장 다.

    friend std::ostream & operator<<(std::ostream & out, 
                                     const Student & stu) 
    { 
        out << stu.stdId << ',' <<stu.roll << ','<< stu.name... <<'\n'; 
        return out;
    } 

데이터를 다시 읽는 것은 약간 까다 롭습니다.

    friend std::istream & operator>>(std::istream & in, 
                                     Student & stu) 
    { 
        std::string line;
        if (std::getline(in, line))
        {
            std::stringstream strm(line);
            if (!(strm >> stu.stdId >> comma >> stu.roll >> comma) ||
                !std::getline(strm, stu.name, ',') ||
                !std::getline(strm, stu.dob, ',') ||
                ...))
            { // If any read failed, mark the stream as failed so the caller knows.
                out.setstate(std::ios_base::failbit);
            }
        }
        return out;
    } 
1 ytlu Nov 29 2020 at 06:47

먼저, 사소한 트릭으로 클래스에 대한 빈 생성자를 추가하여 모든 멤버, 정수 {0} 및 string {}을 초기화하면 원하지 않는 gabages를 줄일 수 있습니다.

 Student::Student() :stdId(0), roll(0), name{}, dob{}, phone{}, address{} {;}

주요 문제는 가져온 Student 배열을 삭제하는 fetchfomrfile () 함수에서 발생했기 때문에 호출자는 정의되지 않은 데이터 배열을 받았습니다.

Student* fetchFromFile()
{
  int i=0;
  Student obj;
  Student* returnObj = new Student[MAX];

  //reading records from file
  fin.close();
  delete[] returnObj;// <<<< youe deleted
  return returnObj; // and return it as undefined
}

파일 크기를 계산할 수 있으므로 호출자 함수에서 제안합니다.

void search_student(){
 // Student* student = fetchFromFile();
    Student *student = new Stduent [getFileSize()];
     fecchFromFile(student); // use this array in fetch_file 
  // other things
 }

fetchFromFile을 다음과 같이 다시 작성하십시오.

viod fetchFromFile(Stduent *ss)
{
  // read file data to array ss[i];
}