Sachin Bhusal
Sachin Bhusal

Reputation: 63

How to read from file and store in array of objects in c++

I am learning c++ and have a trouble in file handling. I am writing a code as a homework where i have to write objects into a file and then read those objects as array from the file at once. Here is my code:

#include <iostream>
#include <fstream>

using namespace std;

class Records{
    char* name;
    int roll;
public:
    Records()
    {
        name = new char[20];
    }
    void setData()
    {
        cout<<"Enter name: "<<endl;
        cin>>name;
        cout<<"Enter roll"<<endl;
        cin>>roll;
    }
    char* getname()
    {
        return name;
    }
    int getRoll()
    {
        return roll;
    }
    void operator = (Records& no)
    {
        name = no.name;
        roll = no.roll;
    }
};

int main()
{
    int i =0 ;
    Records rec;
    rec.setData();
    Records::increase();
    ofstream fout;
    fout.open("file.txt", ios::app);
    fout.write((char*)&rec, sizeof(rec));
    fout.close();

    Records* results = new Records[20];
    Records rec1;
    ifstream fin;
    fin.open("file.txt", ios::in);
    while(!fin.eof())
    {
        fin.read((char*)&rec1, sizeof(rec1));
        results[i] = rec1;
        i++;
    }
    fin.close();
    cout<<results[0].getRoll();
    return 0;
}

So basically, I made a Records class and store its object in a file. That works fine but I faced problem while taking data from file. It is not showing anything or sometimes showing garbage value. Anyone have better idea please hep me. Thanks in advance!

Upvotes: 0

Views: 1763

Answers (2)

ytlu
ytlu

Reputation: 412

After fixed some other errors, I post this final version for you reference. Note that this project cannot use dynamic allocation for the field "name". Using dynamic allocation, the 20-byte of "name" is not counted as the size of class Records, and the pointer itself is not transferable. It causes read/write error in the field "name".

#include <iostream>
#include <fstream>
#include <algorithm>
using namespace std;

class Records{
    char name[20];
    int roll;
public:
    Records()
    {
      //  name = new char[20];
    }
    void setData()
    {
        cout<<"Enter name: "<<endl;
        cin>>name;
        cout<<"Enter roll"<<endl;
        cin>>roll;
    }
    const char* getname() const
    {
        return name;
    }
    int getRoll() const
    {
        return roll;
    }
    Records& operator = (const Records& no)
    {
        std::copy_n(no.name, 20, this->name);
        roll = no.roll;
        return *this;
    }
};
int main()
{
    int i =0, c ;
    std::string a;
    Records rec;
    ofstream fout;
    fout.open("file.txt", std::ofstream::binary);
    c = 0;
    while (1)
    {
       std::cout << "Input record [" << c << "] ? (y/n) ";
       std::cin >> a;
       if (a[0]=='y' || a[0]=='Y')
        {
          rec.setData();
          fout.write((char*)&rec, sizeof(rec));
          ++c;
        }
        else break;
    }
    fout.close();
// output 
    Records* results = new Records[20];
    Records rec1;
    ifstream fin;
    fin.open("file.txt", std::ifstream::binary);
    while(!fin.eof())
    {
       fin.read((char*)&rec1, sizeof(rec1));
       results[i] = rec1;
       i++;
    }
   fin.close();
   // eidt to print all records
   for (int j=0; j<(i-1); j++)
    {  std::cout << "record # = " << j << std::endl;
       std::cout << "   name = " << results[j].name;
       std::cout << "   roll = " << results[j].roll << std::endl;
    }

   return 0;
}

A test run

$ ./a.exe
Input record [0] ? (y/n) y
Enter name:
aaaa
Enter roll
1234
Input record [1] ? (y/n) y
Enter name:
bbbb
Enter roll
2345
Input record [2] ? (y/n) y
Enter name:
cccc
Enter roll
3456
Input record [3] ? (y/n) n
1234

Upvotes: 0

ytlu
ytlu

Reputation: 412

First, you have to open file in binary mode for read and write.

 std::ofstream fou("out_filename",std::ofstream::binary);
 std::ifstream fin("in_filename", std::ifstream::binary);

Secondly, you assign operator=() is problematical. It assigns two records using the same address. Therefore in the reading process, all 20 elements in result[i] were all sharing the address of rec1::name. You have to correct the operator=() by copying contents of name.

This is not good.

void operator = (Records& no)
{
    name = no.name;
    roll = no.roll;
}

Rewrite as follows:

Edit: since your objects are all initially assigned with its memory. The new allocation is not necessary.

Records& Records::operator=(const Records& no)
{
   // this->name = new char [20]; 
    std::copy_n(no.name, 20, this->name); // include <algorithm>
    roll = no.roll;
    return *this; // return current object for another =.
}

Finally, add a destructor

Records::~Records() {
delete [] this->name; }

Good luck!

Upvotes: 1

Related Questions