You must choose / design a file format for storing your data.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
|
#include <iostream>
#include <limits>
#include <string>
// In C++ you can forget C-strings
// It’ll make your life 7-bazillion times easier
struct album
{
std::string title, artist;
int year, price, stock;
};
// There are options for storing data as TEXT
// The simplest might simply be to take three lines for each record:
// title
// artist
// year price stock
std::ostream & operator << ( std::ostream & outs, const album & A )
{
return outs
<< A.title << "\n"
<< A.artist << "\n"
<< A.year << " " << A.price << " " << A.stock << "\n";
}
// Such a format makes it really, really easy to read a record:
std::istream & operator >> ( std::istream & ins, album & A )
{
getline( ins, A.title );
getline( ins, A.artist );
ins >> A.year >> A.price >> A.stock;
ins.ignore( std::numeric_limits<std::streamsize>::max(), '\n' );
return ins;
}
#include <cmath>
#include <fstream>
#include <vector>
int main()
{
// likewise, you can use a vector instead of an array for sanity
std::vector <album> albums;
// Reading a file of albums is child’s play now:
{
std::ifstream f( "intrare.in" );
album A;
while (f >> A) albums.push_back( A );
}
// Let’s apply a little inflation to all the prices:
for (album & A : albums)
A.price = (int)round( A.price * 1.1 );
// And writing a file is just as easy:
{
std::ofstream f( "example.txt" );
for (const album & A : albums)
f << A;
}
}
|
intrare.in
album one
somebody awesome
1990 1150 1
album two
another artist
2001 1499 2 |
The file format suggested here is nice because it is flexible (album and artist names
may be more than 99 characters) but in general saves you space (most album and artist names are less than 99 characters). Using multiple lines makes reading and writing them extra easy — the only character(s) that are forbidden in an artist and album name are newlines.
Another option would be to use a simple CSV-style format, which for your simple case can be done strictly as:
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
|
std::ostream & operator << ( std::ostream & outs, const album & A )
{
return outs
<< quoted( A.title ) << ","
<< quoted( A.artist ) << ","
<< A.year << "," << A.price << "," << A.stock << "\n";
}
std::istream & operator >> ( std::istream & ins, const char c )
{
if (ins.peek() == c) ins.get();
else ins.setstate( std::ios::failbit );
return ins;
}
std::istream & operator >> ( std::istream & ins, album & A )
{
return ins
>> quoted( A.title ) >> ','
>> quoted( A.artist ) >> ','
>> A.year >> ','
>> A.price >> ','
>> A.stock >> '\n';
}
|
intrare.in
"album one","somebody awesome",1990,1150,1
"album two","another artist",2001,1499,2 |
You’ll notice the extra helper extraction function I added there to read an expected character (commas or newlines). You could have done this using
getline()
+
istringstream
or again used
istream::ignore()
, but I personally find this simplest and easiest to read.
This particular helper does not deal with whitespace around commas in your CSV, so if you expect a human to manually manipulate it you can fix things by adding it explicity:
29 30 31 32 33 34 35 36 37
|
std::istream & operator >> ( std::istream & ins, album & A )
{
return ins
>> quoted( A.title ) >> std::ws >> ','
>> quoted( A.artist ) >> std::ws >> ','
>> A.year >> std::ws >> ','
>> A.price >> std::ws >> ','
>> A.stock >> std::ws; // this eats '\n' too
}
|
The CSV format
does allow newlines in the album and artist names. I don’t think it is worth the problems that CSV adds, though.
Finally, if you must use an array, make sure to name things well and check that you don’t overflow bounds:
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
|
#include <ciso646>
#include <cmath>
#include <fstream>
int main()
{
const int MAX_ALBUMS = 100;
album albums[MAX_ALBUMS];
int album_count = 0;
// Reading a file of albums is child’s play now:
{
std::ifstream f( "intrare.in" );
while ((album_count < MAX_ALBUMS) and (f >> albums[album_count]))
album_count += 1;
}
// Let’s apply a little inflation to all the prices:
for (int n = 0; n < album_count; n += 1)
albums[n].price = (int)round( albums[n].price * 1.1 );
// And writing a file is just as easy:
{
std::ofstream f( "example.txt" );
for (int n = 0; n < album_count; n += 1)
f << albums[n];
}
}
|
If you with to write your data in a
binary format that is a different thing. Let me know and I’ll run down the (good) options with that.