Issue with file
Jul 4, 2020 at 7:06am UTC
Hi guys,
I'm currently attempt to write output on a file but overtime I do the address never shows and the output ends up coming out like this on misc.doc.
$
Name: kyle jordan ! – `
Zip: 84753
Could someone please show me how to correct this ? Thank you
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
#include <iostream>
#include <string>
#include <fstream>
using namespace std;
struct structure
{
string name,address,zip;
};
int main()
{
structure kyle;
fstream file;
string misc = "misc.doc" ;
file.open(misc.c_str(),ios::out);
char option;
do
{
cout << "Name: " ;
getline(cin,kyle.name);
kyle.name = "\nName: " + kyle.name;
cout << "\nAdress: " ;
getline(cin,kyle.address);
kyle.address = "\nAdress: " + kyle.address;
cout << "\nZip: " ;
getline(cin,kyle.zip);
kyle.zip = "\nZip: " + kyle.zip;
file.write(reinterpret_cast <char *>(&kyle), sizeof (kyle));
cout << "\nWrite again (Y/N): " ;
cin >> option;
option = toupper(option);
}while (option=='Y' );
file.close();
cout << endl;
return 0;
}
Jul 4, 2020 at 8:42am UTC
You can't do file.write() on classes that contain non-POD types.
https://stackoverflow.com/questions/146452/what-are-pod-types-in-c
You see, a std::string inside your class is itself a fixed size. The string you store is elsewhere in memory, and somewhere that simplistic write() knows nothing about.
The whole subject of serialisation is just a whole can of worms.
https://isocpp.org/wiki/faq/serialization
Anyhoo - example time.
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
#include <iostream>
#include <string>
#include <cstring>
#include <fstream>
#include <limits>
using namespace std;
struct string_record {
string name, address, zip;
};
struct array_record {
char name[32];
char address[64];
char zip[32];
};
int main()
{
string_record kyle;
array_record minogue = { 0 };
ofstream f1("string_rec.dat" ,ios::binary);
ofstream f2("string_rec.txt" );
ofstream f3("array_rec.dat" ,ios::binary);
char option;
do {
cout << "Name: " << flush;
getline(cin, kyle.name);
kyle.name = "Name: " + kyle.name;
cout << "Adress: " << flush;
getline(cin, kyle.address);
kyle.address = "Adress: " + kyle.address;
cout << "Zip: " << flush;
getline(cin, kyle.zip);
kyle.zip = "Zip: " + kyle.zip;
strcpy(minogue.name,kyle.name.c_str());
strcpy(minogue.address,kyle.address.c_str());
strcpy(minogue.zip,kyle.zip.c_str());
f1.write(reinterpret_cast < char *>(&kyle), sizeof (kyle));
f2 << kyle.name << "\n"
<< kyle.address << "\n"
<< kyle.zip << "\n" ;
f3.write(reinterpret_cast < char *>(&minogue), sizeof (minogue));
cout << "Write again (Y/N): " ;
cin >> option;
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n' );
option = toupper(option);
} while (option == 'Y' );
return 0;
}
$ g++ baz.cpp
$ ./a.out
Name: Fred Flintstone
Adress: 1, Bedrock Drive
Zip: 1234
Write again (Y/N): y
Name: Barney Rubble
Adress: 2, Bedrock Drive
Zip: 1234
Write again (Y/N): n
$ hd -v array_rec.dat
00000000 4e 61 6d 65 3a 20 46 72 65 64 20 46 6c 69 6e 74 |Name: Fred Flint|
00000010 73 74 6f 6e 65 00 00 00 00 00 00 00 00 00 00 00 |stone...........|
00000020 41 64 72 65 73 73 3a 20 31 2c 20 42 65 64 72 6f |Adress: 1, Bedro|
00000030 63 6b 20 44 72 69 76 65 00 00 00 00 00 00 00 00 |ck Drive........|
00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000060 5a 69 70 3a 20 31 32 33 34 00 00 00 00 00 00 00 |Zip: 1234.......|
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000080 4e 61 6d 65 3a 20 42 61 72 6e 65 79 20 52 75 62 |Name: Barney Rub|
00000090 62 6c 65 00 65 00 00 00 00 00 00 00 00 00 00 00 |ble.e...........|
000000a0 41 64 72 65 73 73 3a 20 32 2c 20 42 65 64 72 6f |Adress: 2, Bedro|
000000b0 63 6b 20 44 72 69 76 65 00 00 00 00 00 00 00 00 |ck Drive........|
000000c0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000d0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
000000e0 5a 69 70 3a 20 31 32 33 34 00 00 00 00 00 00 00 |Zip: 1234.......|
000000f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000100
$ hd -v string_rec.dat
00000000 30 bb 16 01 00 00 00 00 15 00 00 00 00 00 00 00 |0...............|
00000010 1e 00 00 00 00 00 00 00 6e 74 73 74 6f 6e 65 00 |........ntstone.|
00000020 00 bb 16 01 00 00 00 00 18 00 00 00 00 00 00 00 |................|
00000030 1e 00 00 00 00 00 00 00 63 6b 20 44 72 69 76 00 |........ck Driv.|
00000040 a0 83 1d b8 fe 7f 00 00 09 00 00 00 00 00 00 00 |................|
00000050 5a 69 70 3a 20 31 32 33 34 00 8d 52 83 7f 00 00 |Zip: 1234..R....|
00000060 30 bb 16 01 00 00 00 00 13 00 00 00 00 00 00 00 |0...............|
00000070 1e 00 00 00 00 00 00 00 6e 74 73 74 6f 6e 65 00 |........ntstone.|
00000080 00 bb 16 01 00 00 00 00 18 00 00 00 00 00 00 00 |................|
00000090 1e 00 00 00 00 00 00 00 63 6b 20 44 72 69 76 00 |........ck Driv.|
000000a0 a0 83 1d b8 fe 7f 00 00 09 00 00 00 00 00 00 00 |................|
000000b0 5a 69 70 3a 20 31 32 33 34 00 8d 52 83 7f 00 00 |Zip: 1234..R....|
000000c0
$ hd -v string_rec.txt
00000000 4e 61 6d 65 3a 20 46 72 65 64 20 46 6c 69 6e 74 |Name: Fred Flint|
00000010 73 74 6f 6e 65 0a 41 64 72 65 73 73 3a 20 31 2c |stone.Adress: 1,|
00000020 20 42 65 64 72 6f 63 6b 20 44 72 69 76 65 0a 5a | Bedrock Drive.Z|
00000030 69 70 3a 20 31 32 33 34 0a 4e 61 6d 65 3a 20 42 |ip: 1234.Name: B|
00000040 61 72 6e 65 79 20 52 75 62 62 6c 65 0a 41 64 72 |arney Rubble.Adr|
00000050 65 73 73 3a 20 32 2c 20 42 65 64 72 6f 63 6b 20 |ess: 2, Bedrock |
00000060 44 72 69 76 65 0a 5a 69 70 3a 20 31 32 33 34 0a |Drive.Zip: 1234.|
00000070
$ cat string_rec.txt
Name: Fred Flintstone
Adress: 1, Bedrock Drive
Zip: 1234
Name: Barney Rubble
Adress: 2, Bedrock Drive
Zip: 1234
Some things to notice.
1. Using write() to save non-POD data doesn't save much of anything. Sure, there are fragments, hints and suggestions of things that might have been stored in strings at one time or another.
2. Using write() to save POD data works, but takes up a lot of wasted space if strings are shorter than the size you allocated, and inflexible if you want to make them longer.
Look carefully at the 'e' byte at offset 0x94 - that's the 'e' from the end of the longer string on the previous round of input. Information leakage is an issue if you're not careful.
Jul 4, 2020 at 9:51am UTC
Thank you for your help Salem this helps a lot. What would you recommend as the most practical way to output data on classes that contain non-POD types? Thank you again.
Kyle
Jul 4, 2020 at 11:16am UTC
Making each class responsible for overloading << and >> is one way.
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
#include <iostream>
#include <ostream>
#include <string>
#include <cstring>
#include <fstream>
#include <limits>
using namespace std;
struct string_record {
string name, address, zip;
friend ostream & operator <<(ostream& os, const string_record& rec) {
os << rec.name << "\n"
<< rec.address << "\n"
<< rec.zip << "\n" ;
return os;
}
};
int main()
{
string_record kyle;
ofstream f2("string_rec.txt" );
char option;
do {
cout << "Name: " << flush;
getline(cin, kyle.name);
kyle.name = "Name: " + kyle.name;
cout << "Adress: " << flush;
getline(cin, kyle.address);
kyle.address = "Adress: " + kyle.address;
cout << "Zip: " << flush;
getline(cin, kyle.zip);
kyle.zip = "Zip: " + kyle.zip;
f2 << kyle;
cout << "Write again (Y/N): " ;
cin >> option;
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n' );
option = toupper(option);
} while (option == 'Y' );
return 0;
}
Jul 4, 2020 at 7:59pm UTC
This is perfect thanks Salem!
Topic archived. No new replies allowed.