0

I am working on a phone book project in C++. I made a class and have string objects inside to store some strings.

My Program is unable to write the string data into the file and is troubling me. It only shows me the last data inserted.

Here is the sample program giving the basic idea of what I want to do and where does the problem reside.

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

class student {
private:
    string name;    
    int age;    
    string mail;
public:
    void getData(student &s) {
        ofstream file;
        file.open("file.txt", ios::app);
        if(!file) {
            cout << "Error in creating file.." << endl;
            return;
        }
        cout << "\nFile created successfully." << endl;

        cout << "Enter name:    ";
        cin.ignore(); 
        getline(cin, name);

        cout << "Enter age:     ";
        cin >> age;

        cout<<"Enter mail:    ";
        cin.ignore(); 
        getline(cin, mail);

        file.write((char*)&s, sizeof(s));
        file.close();

        cout << "\nFile saved and closed succesfully." << endl;
    }
    void showData(student &s) {
        ifstream file1;
        file1.open("file.txt", ios::in);
        if(!file1){
            cout<<"Error in opening file..";
            return;
        }
        while(!file1.eof()){
             file1.read((char*) &s, sizeof(s));
             cout << "Name: " <<name << "\nAge : " << age << "\nMail: "<< mail << endl; 
        }
        file1.close();
    }
};
int main() {
    student s;
    s.getData(s);
    s.getData(s);
    s.getData(s);
    s.showData(s);
    return 0;
}

I need help in this case.

Output Image

kiner_shah
  • 2,055
  • 3
  • 22
  • 29
  • Unrelated to your problem, but please read [Why is iostream::eof inside a loop condition considered wrong?](https://stackoverflow.com/questions/5605125/why-is-iostreameof-inside-a-loop-condition-considered-wrong) – Some programmer dude Nov 20 '18 at 15:08
  • The concept you're looking for is called (de-)[serialization](https://en.wikipedia.org/wiki/Serialization). Dumping a binary blob containing `std::string` objects isn't going to work for that. – Useless Nov 20 '18 at 15:17
  • You are passing `s` as reference, but not filling any values in its members. Do you intend to fill age, name, mail in `s`? – kiner_shah Nov 20 '18 at 15:35

2 Answers2

2

A std::string object is basically nothing more than a wrapper around a pointer (to the actual string contents). A pointer is unique for each process and can not readily be shared between processes even on the same system, not even processes running the very same program.

For you to be able to read or write write a raw object like you do, the object needs to be trivial, which your object isn't since it contains the non-trivial std::string members.

Some programmer dude
  • 363,249
  • 31
  • 351
  • 550
0

A std::ifstream provides the same interface as std::cin and a std::ofstream provides the same interface as std::cout. Rather than copying the bytes that denote your object, you can use a function to read and write to the appropriate stream.

class student {
private:
    string name;
    int age;    
    string mail;
public:
    void getData();
    void showData();
};

std::istream& operator >> (std::istream& is, const student & s)
{
    is.ignore(); std::getline(is, s.name);
    is >> s.age;
    is.ignore(); std::getline(is, s.mail);
    return is;
}

std::ostream& operator << (std::ostream& os, const student & s)
{
    return os << s.name << s.age << s.mail;
}

You also don't need to pass an object to it's own methods. You use the members, but then read or write the passed student.

void student::getData() {
    std::ofstream file("file.txt",ios::app);
    if(!file) {
        std::cout << "Error in creating file.." << std::endl;
        return;
    }
    std::cout << "\nFile created successfully." << std::endl;

    std::cout << "Enter name:    ";
    std::cin.ignore(); 
    std::getline(std::cin, name);

    std::cout << "Enter age:     ";
    std::cin >> age;

    std::cout << "Enter mail:    ";
    std::cin.ignore(); 
    std::getline(std::cin, mail);

    file << *this;
    std::cout << "\nFile saved and closed succesfully." << std::endl;
}

void student::showData() {
    ifstream file1("file.txt", ios::in);
    if(!file1){
        std::cout << "Error in opening file..";
        return;
    }
    while(file1 >> *this){
         std::cout << "Name: " << name << "\nAge : " << age << "\nMail: " << mail << std::endl; 
    }
}

int main() {
    student s;
    s.getData();
    s.getData();
    s.getData();
    s.showData();
    return 0;
}

But getData and showData don't really belong to student. I would change it to void getStudent(std::istream & src, std::ostream & dest) and void showStudents(std::istream & src, std::ostream & dest), passing in cin, cout and the file stream from main.

Caleth
  • 35,377
  • 2
  • 31
  • 53