- std::string to klasa, więc s[i].imie czy s[i].kierunek są obiektami.
- sizeof da ci rozmiar w bajtach obiektu. W skład obiektu std::string wchodzi m.in. wskaźnik do pamięci z ciągiem znaków. Wskaźnik, nie sama pamięć. Tzn. zakładając, że std::string składa się z 4-bajtowego unsigned inta oraz 8-bajtowego wskaźnika, to sizeof(s[i].imie) da ci 12 (lub ewentualnie może to być nieco więcej ze względu na jakiś padding między intem a wskaźnikiem - zależne od kompilatora, ale nie o tym mowa) - długość stringa nie ma tu nic do rzeczy
- &s[i].imie da ci wskaźnik do obiektu std::string, nie do pamięci z ciągiem znaków
Zatem aby wpisać do pliku zawartość stringa:
plik.write(s[i].imie.c_str(), s[i].imie.length());
Podobna historia z odczytem. Nie możesz sobie po prostu zczytać do pamięci w której jest obiekt string. Do bufora stringa też nie o ile wcześniej nie wymusiłeś alokacji wystarczającej ilości pamięci. Najbezpieczniejszy wg mnie byłby taki sposób:
char buf[1u<<10]; //1024 bajty
streamsize sz = /*ile znakow?*/;
plik.read(buf, sz);
buf[sz] = 0; // wstawiamy terminating zero na koniec zaladowanego ciagu znakow aby operator przypisania ponizej wiedzial gdzie ma zakonczyc kopiowanie
p.imie = buf; // operator przypisania std::string skopiuje sobie znaki z `buf`
Musisz tylko wiedzieć ile znaków chcesz wczytać czego obecnie najwyraźniej nie wiesz. `sizeof(p.imie)` na pewno magicznie ci tego nie powie.