EddieV223
EddieV223

Reputation: 5303

ofstream ifilestream and using cin to get an array of chars?

So I am learning how to use streams to make files of my own type, I have a simple version of it working like this

struct Appointment
{

Appointment()
{

}
// 

//and int to represent a certain doctor
int doctorID;  // an enum to be made later

int year; // 1950 - 2050    100 years total

int month; // 0 - 11  

int day; // 0 - 31   

int hour; // 0 - 23


int minute; // 0 - 59
    static Appointment GetDataFromUser()
{
    Appointment appoint = Appointment();

    cout << "\nEnter a Doctor ID :" << endl;
    cin >> appoint.doctorID;

    cout << "\nEnter a year 1900 - 3000 :" << endl;
    cin >> appoint.year;

    cout << "\nEnter a month 0 - 11 :" << endl;
    cin >> appoint.month;

    cout << "\nEnter a day of month 0 - 31 :" << endl;
    cin >> appoint.day;

    cout << "\nEnter an hour 0 - 23 :" << endl;
    cin >> appoint.hour;

    cout << "\nEnter an minute 0 - 59 :" << endl;
    cin >> appoint.minute;

    cout << "\nAll values entered thank you!" << endl;

    return appoint;

}
};

then somewhere I use

ifstream ifilestream( fileName.c_str(), std::ios_base::in | std::ios::binary );

Appointment appoint;

ifilestream.read((char *)&appoint, sizeof(Appointment));

and

ofstream ofilestream( fileName.c_str(), std::ios_base::out | std::ios::binary );

Appointment appoint = Appointment::GetDataFromUser();

ofilestream.write((char *)&appoint, sizeof(Appointment));

This works ok but I want to replace the int doctorID with a char doctorID[ length ] length could = 20 or something, to store the doctors name with spaces and . For example a user could enter "Dr. Watson" or just "Watson".

But when I do and use cin to get that info it breaks the code cause of spaces or whatever I'm not sure. So whats the proper way to do that?

And a second question is, what if i wanted the length of the char[] to be decided when the user enters it?

Upvotes: 2

Views: 583

Answers (2)

HighCommander4
HighCommander4

Reputation: 52749

To input a string that contains spaces, use cin.getline(), which reads up to a newline:

char doctorID[20]; 
...
cout << "\nEnter a Doctor ID :" << endl;
cin.getline(appoint.doctorID, 20);

If you want a string whose size is determined at runtime, you should use std::string, which can be dynamically resized.

However, if you use std::string, you will no longer be able to read and write your structure to/from file the way you do now. (*) You can either:

  1. Switch to a text-based file format
  2. Write your own functions for serializing/deserializing an std::string to a binary file
  3. Use a serialization library like Boost.Serialization

(*) because right now you're just writing the structure exactly as it is represented in memory; however std::string's representation is really just a pointer to another memory location

Upvotes: 3

totowtwo
totowtwo

Reputation: 2147

Don't reinterpret your struct as a data pointer! This binds it to whatever in-memory representation your current compiler produces. If you ever change anything about your program, your streaming would break.

For output, the first step is to write an operator<<(ostream& out, Appointment const& app); function. Generally you want this to be a free function that is a friend of your class

struct Appointment
{
    // previous contents
    friend ostream& operator<<(ostream& out, Appointment const& app);
};
ostream& operator<<(ostream& out, Appointment const& app)
{
    out << app.doctorID << std::endl;
    // out << app.OtherField for each field
    return out;
}

Then you can ofilestream << appoint;. Write the symmetric operator for input, but you can ignore the whitespace. Use std::string instead of char[]. The most generic solution for serialization would be to use the boost::Serialization framework. But it is overkill for this problem.

Upvotes: 1

Related Questions