Issue with file

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;
}
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.

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
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;
}

This is perfect thanks Salem!
Topic archived. No new replies allowed.