After two days of working on this, I have to raise the white flag. The problem says to create an array of structures (three of them), and write them via binary output to a file. Then, open that file, capture all of the data, and ask the user which of the three books he/she wants information about. I am to use the seekg function to align the starting read point based on the user input.
I get the file to write, and I can also retrieve the first and third record - the second record's title is not displaying correctly, and all three crash after the display. Any help would be very much appreciated!
#include<iostream>
#include<fstream>
#include<string>
usingnamespace std;
struct Book
{
string title;
int numPages;
};
constint numBooks = 3; //constant int for 3 books
int main()
{
fstream bookFile;
bookFile.open("books.txt", ios::out | ios::binary); // declare file object and use binary output
if (bookFile)
{
Book bookArray[numBooks] = { { "C++ Programming", 1000 }, // book array with 3 books
{ "Java Programming", 1250},
{ "Head First C", 750 } };
cout << "Writing book array to file...." ;
bookFile.write(reinterpret_cast<char *>(bookArray), sizeof(bookArray));
cout << "Successful. " << endl << endl;
}
else
cout << "Error opening output file. Program aborting. " << endl;
bookFile.close();
fstream inputBookFile; //declare new book file for input use
inputBookFile.open("books.txt", ios::in | ios:: binary); // open inputBookFile books.txt in binary input mode
Book outputBook; // book type to hold read data
long fileByteNumber; // variable to hold the byte number of file
int userInt; // variable to hold user choice of which book # info to display
if (inputBookFile) //if file opened successfully, continue
{
cout << "Please enter a number from 1 - 3." << endl;
cout << "The corresponding book information will be shown. ";
cin >> userInt; // capture user choice
cout << endl;
cout << "Here is the information for book #" << userInt << ": " << endl;
userInt--; //decrement user's # to start at 0
fileByteNumber = (sizeof(Book) * userInt);
inputBookFile.seekg(fileByteNumber, ios::beg); //uses byteNumber to locate correct record from the beginning of the file
inputBookFile.read(reinterpret_cast<char *>(&outputBook), sizeof(outputBook));
cout << "Title: " << outputBook.title << endl;
cout << "Pages: " << outputBook.numPages << endl << endl;
}
else //if error opening books file, abort
cout << "Error opening books file. Program aborting. " << endl;
inputBookFile.close(); // close output file
return 0;
}
You can only save trivial types using write. string is not trivial. Actually it is mandatory that string contains at least one pointer, so you are saving a pointer. And all pointer values are different each launch. Only reason that some data was read succesfully, it that memory belonging to originals was not overwritten yet.
Thanks MiiNiiPaa. Would I be correct in assuming that I need to create a char* for the title field? Can you assist me with the syntax? The fact that it is an element of an array of structures is throwing me off.
for (int i = 0; i < 3; i++)
{
const char *p = bookArray[i].title.c_str();
}
I attempted to change the 3 titles using the above for loop, but with the same results. Thanks
Would I be correct in assuming that I need to create a char* for the title field?
You would still saving pointer and not value.
Here are some solutions:
1) Use a character array. It is contained inside structure itself and safe to copy. Generally you can safely read/write only types which are TriviallyCopiable: http://en.cppreference.com/w/cpp/types/is_trivially_copyable
Objects of trivially-copyable types are the only C++ objects that may be safely copied with std::memcpy or serialized to/from binary files with std::ofstream::write()/std::ifstream::read().
2) Serialize stuff yourself instead of relying on builtin read/write. Even better: save stuff in text format, not binary one.
Thanks. The problem is that I must use binary format as well as a string in the actual structure. So unless I can find some way to convert that string to something that can use the .write function, I'm in trouble!