This question has already been answered:

There is a structure

struct User { string login; string password; }; 

The goal is to make a primitive user authorization. Those. a file is created, a filled object of the above structure is written to it, and on subsequent launches a login + password is requested, the data from the file is read and compared. Code:

 #include <iostream> #include <windows.h> #include <fstream> #include <vector> #include <string> using namespace std; struct User { string login; string password; }; void main () { SetConsoleCP (1251); // установка универсальной кодировки SetConsoleOutputCP (1251); string path; int realsize=0; User u; vector <User> U; bool exit = false; do { system("cls"); cout<<"Укажите, на каком диске находится файл с регистрационными данными:\n"; getline(cin, path); path += ":\\users.txt"; ifstream fin(path, ios_base::binary | ios_base::in); if (fin.is_open()) { cout<<"Отлично, ваш файл найден!\n"; fin.read((char*)&u, sizeof(User)); U.push_back(u); fin.close(); cout << "Введите логин:\n"; getline(cin, u.login); cout << "Введите пароль:\n"; getline(cin, u.password); if (!U.at(0).login.compare(u.login) && !U.at(0).password.compare(u.password)) { cout << "Вы авторизованы!\n"; } else { cout << "Вы не авторизованы!\n"; } exit = true; } else { cout << "Файл не найден и будет создан"; ofstream fout (path, ios_base::binary | ios_base::out); if (fout.is_open()) { cout << "Введите логин:\n"; getline(cin, u.login); cout << "Введите пароль:\n"; getline(cin, u.password); fout.write((char*)&u, sizeof(User)); fout.close(); cout << "Файл создан и данные внесены!\n"; } else { cout << "Ошибка при создании файла! Работа приложения будет завершена.\n"; exit = true; } } } while(!exit); system("pause"); } 

The trouble is that when executing this code, an error appears:

Unhandled exception at address 0x0FDECCC8 (msvcp110.dll) in test.exe: 0xC0000005: access violation when reading at 0x0067ADE4.

Call stack frames:

call stack

It was established through experiments that replacing the use of a vector with a simple dynamic array does not affect the error (that is, it still appears), but replacing the use of string with char * eliminates the manifestation of this error. Googling, I came to the conclusion that there is some kind of error in the string destructor (I could be wrong). Can someone clarify the situation and give recommendations on the correct use of the string type in this kind of tasks?

Reported as a duplicate by Harry c ++ May 11 at 3:36 .

A similar question was asked earlier and an answer has already been received. If the answers provided are not exhaustive, please ask a new question .

  • And why do you open the file as a binary and read the line? Try removing flags in the method .open (path) - pavel

3 answers 3

The easiest way (as already mentioned in @pavel comments ) is to use text mode for working with a file and formatted input / output operator<< ( operator<< , operator>> ) to read / write std::string from / to the stream.

Reading:

 ifstream fin(path); if (fin) { fin >> u.login >> u.password; } 

Record:

 ofstream fout(path); if (fout) { // Разделители нужны для последующего считывания fout << u.login << " " << u.password << "\n"; } 

At the same time, this approach imposes some restrictions on strings: at least they should not contain whitespace characters, since such a character will be regarded as a separator.

The functions istream::read , ostream::write in this case are not used at all. The reason why they do not work as it should be indicated in the answer @gbg.

  • @VladimirGamalian is already written about this :) The main thing is the idea, and how to share the data is already particular. - αλεχολυτ
  • Who reads the answers to the end) - Vladimir Gamalyan
  • @VladimirGamalian let's hope that at least the vehicle reads :) - αλεχολυτ
  • @alexolut will read, of course :) thanks for the detailed explanations and correct answer, but the first was Vladimir Gamalian :) - LivAlex
  • @LivAlex for the sake of justice, check the timestamp of answers :) - αλεχολυτ pm

Write to file using

 fout.write((char*)&u, sizeof(User)); 

actually writes the byte-byte content of the User structure, but since it contains non-POD types ( std::string ), then there is little benefit from this, because The data of your lines is most likely in the heap.

In your case, you can write the username and password to a file (provided that they do not use a line break), one per line, and also read. Example:

 int main() { struct User { std::string login; std::string password; }; { User user{ "login", "password" }; // Пишем логин и пароль в файл в две строчки std::ofstream f("users.txt"); f << user.login << std::endl << user.password; } { User user; // Читаем из файла std::ifstream f("users.txt"); std::getline(f, user.login); std::getline(f, user.password); std::cout << user.login << std::endl << user.password << std::endl; } } 

    This will not work. string not a POD type, that is, an object of type string does not contain these strings, they are placed elsewhere (where the allocator will push them).

    The rule is simple - everything that is not POD cannot simply be taken and copied byte-by-byte.

    The solution is to use POD types for data storage.

     struct mu_ugly_pod { char user_name[100500]; char user_last_name[100500]; }; 

    Such a thing should be written and read without problems. Alas, all conveniences connected with string in this case will be gone.

    • Thanks for the explanation, I tried this method, it is really working, but I thought that there should be a way to preserve the usability of the string type and complete the task. * Went to deepen knowledge on POD - LivAlex
    • one
      @LivAlex needs to bless its serialization wrapper. What ultimately threatens the loss of speed. If speed is critical for you - it’s best to arrange the file mapping to memory and string_range - gbg