0

Is there a way a string could be used instead of a char[] array in the below struct, and still be saved to a file using read and write functions without getting a runtime error?

#include <iostream>
#include <cstdlib>
#include <fstream>

using namespace std;

struct details
{
    char name[30];
    int add_year;
};

const char * file = "students.dat";

int main()
{
    details x;
    ifstream ifile;
    ifile.open(file,ios_base::in|ios_base::binary);
    if(ifile.is_open())
    {
        cout<<"Contents of "<<file<<" is"<<endl;
        while(ifile.read((char *)&x,sizeof x))
        {
            cout<<x.name<<" - "<<x.add_year<<endl;
        }
        ifile.close();
    }
    ofstream ofile(file,ios_base::out|ios_base::app|ios_base::binary);
    if(!ofile.is_open())
    {
        cerr<<"Can't open "<<file<<endl;
        exit(EXIT_FAILURE);
    }
    cout<<"Name"<<endl;
    cin.get(x.name,30);
    cout<<"Year added"<<endl;
    cin>>x.add_year;
    ofile.write((char *) &x, sizeof x);
    ofile.close();
    cin.get();
    return 0;
}
3
  • 1
    Look up serialization. That will show you how this should be done Commented Dec 7, 2016 at 19:22
  • Most of it where only about the definition "converting objects into binary data streams...". Commented Dec 7, 2016 at 19:31
  • A character array can have advantage because it is fixed in length. Commented Dec 7, 2016 at 19:32

1 Answer 1

1

A std::string (or any other dynamic sized container) contains a pointer to its character data that is stored elsewhere in memory. If you were to read()/write() the std::string itself as-is, you would only be reading/writing the pointer value, not the actual character data. This is not the case with a fixed array.

In order to use std::string in your struct, you would have to (de)serialize the content of the struct back and forth so you can take dynamic data into account.

For example:

#include <iostream>
#include <fstream>
#include <string>
#include <cstdint> 

using namespace std;

struct details
{
    string name;
    int32_t add_year;
};

istream& operator>>(istream &in, details &out)
{
    int32_t len;
    if (in.read((char*) &len, sizeof(len)))
    {
        out.name.resize(len);
        if (len > 0) in.read(&(out.name[0]), len);
        in.read((char*) &(out.add_year), sizeof(out.add_year));
    }
    return in;
}

ostream& operator<<(ostream &out, const details &in)
{
    int32_t len = in.name.size();
    out.write((char*) &len, sizeof(len));
    out.write(in.name.c_str(), len);
    out.write((char*) &(in.add_year), sizeof(in.add_year));
    return out;
}

const char * file = "students.dat";

int main()
{
    details x;

    ifstream ifile;
    ifile.open(file, ios_base::binary);
    if (ifile.is_open())
    {
        cout << "Contents of " << file << " is" << endl;
        while (ifile >> x)
        {
            cout << x.name << " - " << x.add_year << endl;
        }
        ifile.close();
    }

    cout << "Name:" << endl;
    getline(cin, x.name);
    cout << "Year added:" << endl;
    cin >> x.add_year;

    ofstream ofile(file, ios_base::app|ios_base::binary);
    if (!ofile.is_open())
    {
        cerr << "Can't open " << file << endl;
        exit(EXIT_FAILURE);
    }
    ofile << x;
    ofile.close();

    cin.get();
    return 0;
}
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks. It works. But does that mean for every string type being a member of a struct, I must make a separate definition of using read and write like you did with the len in both functions?
@Kinyo356: Reading/writing the string length is just a convenience, not a requirement. You could just read/write a null terminator instead, for instance. Using a length makes memory management a little easier when reading back. But it depends on your particular storage format. But yes, in general, you must serialize any kind of dynamically allocated data, which includes std::string, variable length arrays, etc.
OK. I appreciate the explanation

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.