1

I have created student data to be stored in a binary file but this file is completely broken.

What am I doing wrong?

there was no problem with the text file stored in the notepad.

now after entering after starting the program, it only writes this:

& Ô LC_CTYPE = C; LC_M0 & Ô RIC = C; LC_TIME = C

Is there someone able to help me with this? Have a nice day:)

    #include <iostream>
    #include <fstream>
    #include <string>
    #include <cstdlib>
    
    
    
    using namespace std;
    
    
    
    struct Student{
        string imie;
        string nazwisko;
        int nrAlbumu;
        int wiek;
        float srOcen;
    } dane;
    
    
    
    
    int main(){
    
    
    
    Student dane;
    
    cout << "Podaj imie:" << endl;
    cin >> dane.imie;
    cout << "Podaj nazwisko:" << endl;
    cin >> dane.nazwisko;
    cout << "Podaj nrAlbumu:" << endl;
    cin >> dane.nrAlbumu;
    cout << "Podaj wiek:" << endl;
    cin >> dane.wiek;
    cout << "Podaj srednia ocen:" << endl;
    cin >> dane.srOcen;
    
    
    cout << "Student " << dane.imie  <<" "<< dane.nazwisko << " o numerze albumu: " << dane.nrAlbumu << " ma lat " << dane.wiek << " ma srednia ocen rowna: " << dane.srOcen << endl;
    
    
//-------writing to the file starts here-------------------------

    ofstream ofs("dane.bin", ios::binary);
    
    Student* student = new Student;
    
    student->imie;
    student->nazwisko;
    student->nrAlbumu;
    student->wiek;
    student->srOcen;
    
    ofs.write((char*)(student), sizeof(Student));
    ofs.close();
    
     delete student;
    
 //-------------reading starts here ---------------------------
    
    ifstream ifs("dane.bin", ios::binary);
    
    char* temp = new char[sizeof(Student)];
    ifs.read(temp, sizeof(Student));
    
    Student* student2 = (Student*)(temp);
    
    cout << "Student " << dane.imie  <<" "<< dane.nazwisko << " o numerze albumu: " << dane.nrAlbumu << " oraz ma lat " << dane.wiek << " ma srednia ocen rowna: " << dane.srOcen <<"  Potwierdzenie do zapisu i odczytu!" << endl;
    
    delete student;
    
    
    
    
        return 0;
    }
Pat. ANDRIA
  • 2,330
  • 1
  • 13
  • 27
Man1exter
  • 11
  • 5
  • `ofs.write((char*)(student), sizeof(Student));` -- This will never work. Types that are not trivially copyable cannot be written to binary files like this. You need to serialize the object, not just write raw bytes to a binary file. – PaulMcKenzie Nov 17 '20 at 08:26
  • in what sense should I understand? trivially copyable? I do not understand – Man1exter Nov 17 '20 at 08:30
  • The `Student` object contains `std::string`. That is an object that is not trivially-copyable, thus the `Student` class is not trivially-copyable. If you want more proof, what does `sizeof` do? What value does it return? The `sizeof` is a compile-time value. Now let's say that `std::string` has a `size()` of 1000 characters. The `sizeof` had no idea how many characters **at runtime** the `std::string` will have. Thus that entire line makes no sense and will not work. If you `std::cout << sizeof(Student);` what value do you get? I bet it isn't 1000. – PaulMcKenzie Nov 17 '20 at 08:32
  • [See this](https://stackoverflow.com/questions/27523273/c-properly-writing-stdstring-to-binary-file) and [this](https://stackoverflow.com/questions/523872/how-do-you-serialize-an-object-in-c). Basically you write the *data* to a file, not the object. Then when reading, you read the data and then *recreate* the object from the data. – PaulMcKenzie Nov 17 '20 at 08:35
  • [Here is a quick program explaining the problem](http://coliru.stacked-crooked.com/a/b4d148ed1455746d) – PaulMcKenzie Nov 17 '20 at 08:47
  • in fact, I slowly understand where I made terrible mistakes. I didn't even notice it, it seemed good to me. Thank you in advance for the good advice on action! – Man1exter Nov 17 '20 at 08:51
  • As the program at the link shows, if you used `char` arrays instead of `std::string`, then the struct becomes trivially copyable and then can be used to write to a binary file. However the disadvantage is that you are limited to the number of characters (20 in my example). If you still want to use `std::string`, you have to write the struct in individual pieces, taking care of each `std::string` accordingly. – PaulMcKenzie Nov 17 '20 at 08:53
  • ie then reading and writing to a binary file will work normally with the student file structure? – Man1exter Nov 17 '20 at 08:57
  • I summarized the comments into an answer. Yes, if the struct becomes trivially-copyable, then you can read and write to it with minimal to no other code changes. – PaulMcKenzie Nov 17 '20 at 09:01
  • Many thanks, you are great, I wish you all the best! – Man1exter Nov 17 '20 at 09:04
  • What are these statements: `student->imie; student->nazwisko; student->nrAlbumu;` etc.? What are they supposed to do? – printf Nov 17 '20 at 09:13
  • Operator -> makes it easier for us. Note that the name of the structure variable is a successor. If you wanted to use a dot as with a static one, it would have to look like this: person * shop assistant = new person; // shop pointer * to the address (* shop) .name = "Andrzej"; // same (ugly here) shop-> name = "Andrzej"; // same (nice here) store remove; // delete the object – Man1exter Nov 17 '20 at 09:38

1 Answers1

0

The Student object contains std::string members. That is an object that is not trivially-copyable, thus the Student class is not trivially-copyable, so you cannot simply read and write this type to a binary file by merely copying the bytes to and from the file.

If you want more proof, what does sizeof do? What value does it return? The sizeof is a compile-time value. Now let's say that std::string has a size() of 1000 characters. The sizeof had no idea how many characters at runtime the std::string will have. Thus that entire line makes no sense and will not work.

If you did the following, given that there would be 1000 characters in one of the std::string members:

std::cout << sizeof(Student);

what value do you get? I bet it isn't 1000 or greater.

Here is a quick program illustrating the problem:

#include <type_traits>
#include <string>
#include <iostream>

struct Student{
    std::string imie;
    std::string nazwisko;
    int nrAlbumu;
    int wiek;
    float srOcen;
};

struct Student2{
    char imie[20];
    char nazwisko[20];
    int nrAlbumu;
    int wiek;
    float srOcen;
};

int main()
{
    Student s;
    s.imie = std::string(1000, ' ');
    std::cout << "The number of characters is: " << s.imie.size() << "\n";
    std::cout << "The sizeof(Student) is: " << sizeof(s) << "\n";
    std::cout << "Is Student trivially copyable? " << (std::is_trivially_copyable<Student>()?"Yes":"No") << "\n";
    std::cout << "Is Student2 trivially copyable? " << (std::is_trivially_copyable<Student2>()?"Yes":"No") << "\n";
}

Output:

The number of characters is: 1000
The sizeof(Student) is: 80
Is Student trivially copyable? No
Is Student2 trivially copyable? Yes

Note that if you used char arrays instead of std::string, then the struct becomes trivially copyable and then can be used to write to a binary file in the way you're currently doing it now.

However the disadvantage is that you are limited to the number of characters (20 in my example). If you still want to use std::string, you have to write the struct in individual pieces, taking care of each std::string accordingly as specified by this answer.

PaulMcKenzie
  • 34,698
  • 4
  • 24
  • 45