Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

Wczytywanie struktury za pomocą fread wyrzuca błąd aplikacji

Ostatnio zmodyfikowano 2013-05-13 14:11
Autor Wiadomość
mrwszystko
Temat założony przez niniejszego użytkownika
Wczytywanie struktury za pomocą fread wyrzuca błąd aplikacji
» 2013-05-13 10:28:17
Witam,

 Piszę program, w którym potrzebne mi jest zapisywanie i wczytywanie struktury do pliku. Próbuję to zrobić za pomocą funkcji fwrite oraz fread. Zapisywanie wygląda na poprawnie działające ale gdy chcę odczytać zapisana strukturę funkcją fread to aplikacja wywala okienko z błędem "Wystąpił problem z aplikacją Project1.exe i zostanie ona zamknięta". Oto kod na którym testowałem to zapisywanie i odczytywanie:

C/C++
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

using namespace std;

struct data {
    int dzien;
    int mies;
    int rok;
};

struct towar {
    string nazwa;
    string haslo;
    data data_przyjecia;
} tow;

int main( int argc, char * argv[] )
{
    tow.nazwa = "Test";
    tow.haslo = "test2";
    tow.data_przyjecia.dzien = 12;
    tow.data_przyjecia.mies = 02;
    tow.data_przyjecia.rok = 1999;
   
    FILE * fs;
    fs = fopen( "plik.txt", "w" );
    fwrite( & tow, sizeof( tow ), 1, fs );
    fclose( fs );
   
    FILE * fr;
    fs = fopen( "plik.txt", "r" );
    fread( & tow, sizeof( tow ), 1, fr );
    fclose( fr );
   
    cout << tow.nazwa << endl;
    cout << tow.haslo << endl;
    cout << tow.data_przyjecia.dzien << endl;
    cout << tow.data_przyjecia.mies << endl;
    cout << tow.data_przyjecia.rok << endl;
   
    system( "PAUSE" );
    return EXIT_SUCCESS;
}

Jestem początkujący także jeśli coś prostego spieprzyłem to nie gnojcie mnie za bardzo :P
P-82839
akwes
» 2013-05-13 10:49:10
Problemem może być std::string. Zamiast std::string użyj czegoś co ma stały rozmiar. Na przykład
char nazwa[ 50 ];
. std::string w zależności od implementacji może oferować różne "sztuczki" przechowywania swojej wartości. sizeof(std::string) jest zależne od implementacji i czasami może zwracać stałą wartość dla każdego obiektu std::string, co skutkuje barkiem możliwości poprawnego zapisania i odczytania tego "bajt po bajcie".

 
P-82840
Monika90
» 2013-05-13 10:55:43
Co zwraca sizeof(std::string), to faktycznie zależy od implementacji. Ale pewne jest, że zawsze zwraca stałą znaną już w czasie kompilacji, która oczywiście nie zalezy od długości stringa. To samo dotyczy struktury, która zawiera std::string. Ogólnie, nie można używać fread, fwrite, memset, memcpy, itp. do obiektów które nie są PODami, czyli takich które mają nietrywialny konstruktor kopiujący czy operator przypisania, f. wirtualne i inne rzeczy nie znane w C.

Poza tym, jest i inny błąd, jak używasz binarnego I/O to powinieneś otwierać pliki w trybie binarnym. Warto też sprawdzać czy pliki udało się otworzyć.
P-82841
mrwszystko
Temat założony przez niniejszego użytkownika
» 2013-05-13 11:28:44
Dzięki za informacje :) W takim razie jaka inna funkcja będzie najlepsza do zapisywania struktur, tych bardziej skomplikowanych?
I jeszcze jedno pytanie, czy dozwolone jest zapisywanie struktury, która zawiera jeszcze inna strukturę w sobie?
P-82843
Monika90
» 2013-05-13 12:03:55
Najlepiej to chyba zdefiniować funkcje, które zapisują i wczytują obiekty różnych typów i użyć tych funkcji do implementacji funkcji odczytujacych/zapisujacych bardziej złożone obiekty.
Przykład (pomijający istotne szczegóły takie jak obsługa błędów)
C/C++
const char delimiter = '\n';

void save( std::FILE * file, const std::string & str )
{
    assert( str.find( delimiter ) == std::string::npos );
    std::fwrite( str.data(), str.size(), 1, file );
    std::fputc( delimiter, file );
}

void load( std::FILE * file, std::string & str )
{
    str.clear();
    int ch;
    while( ch = std::fgetc( file ), ch != delimiter && ch != EOF )
         str.push_back( ch );
   
}

void save( std::FILE * file, const data & d ) { std::fwrite( & d, sizeof d, 1, file ); }

void load( std::FILE * file, data & d ) { std::fread( & d, sizeof d, 1, file ); }

void save( std::FILE * file, const towar & tow )
{
    save( file, tow.nazwa );
    save( file, tow.haslo );
    save( file, tow.data_przyjecia );
}

void load( std::FILE * file, towar & tow )
{
    load( file, tow.nazwa );
    laod( file, tow.haslo );
    load( file, tow.data_przyjecia );
}
Chyba jest dobrze, ale używaj tego na własną odpowiedzialność.

P-82848
mrwszystko
Temat założony przez niniejszego użytkownika
» 2013-05-13 14:11:29
Ok. Już chyba sobie poradzę. Wielkie dzięki wszystkim :)
P-82852
« 1 »
  Strona 1 z 1