Problem z vector'ami wskaźnikami itd

0

Witam, chciałbym z góry powiedzieć że kodu jest duży i czasami kod działa super nic się nie dzieje, a czasami wywala się całkowicie z błędem i zawsze wskazuje na koniec funkcji odczytującej dane z pliku:

Debug Assertion Failed:
bla bla bla
Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse)

Kod:

Zacznijmy od struktur:

typedef struct{
    std::string tytul,opis;
    short int godzina,minuta,p_godzina,p_minuta,dzien,miesiac,rok,ID;
} Wydarzenie;

typedef struct{
    std::string username,password,znak_zodiaku,miasto,horoskop;
    int dzien_urodznia, miesiac_urodzenia, rok_urodzenia;
    Pogoda pogoda;
    Biorytm biorytm;
} Profil;

typedef struct{
    std::string kawalek_opisu;
    short int ID;
    GtkWidget* Labels[4];
    GtkWidget* Vbox;
    GtkWidget* Hboxs[2];
    GtkWidget* Event_Box;
} NowyWidget;

Teraz tak naprawdę nie wiem co Wam podać bo kodu jest dużo i sam się nie potrafię zorientować co jest źle, ale mam nadzieję, że pomożecie:

Globalne vectory:

std::vector<Wydarzenie> zbior_wydarzen;
std::vector<NowyWidget> zbior_widgetow;

Zapis/Odczyt z pliku:

int Zapis_Wydarzen(std::vector<Wydarzenie> wydarzenia,Profil profil)
{
    unsigned rozmiar = wydarzenia.size();
    std::cout << rozmiar << std::endl;
    std::ofstream do_pliku;
    std::string nazwa_pliku = "Events/";
    nazwa_pliku += profil.username;
    nazwa_pliku += "-events.event";
    do_pliku.open(nazwa_pliku.c_str(),std::ofstream::binary | std::ofstream::trunc);
    //if (do_pliku.fail()){
    //   if (do_pliku.is_open()) do_pliku.close();
    //  return -1;
    //}
    do_pliku.write((char*)&rozmiar,sizeof(unsigned));
    for (unsigned i = 0; i < wydarzenia.size(); ++i) do_pliku.write((char*)&wydarzenia[i],sizeof(Wydarzenie));
//  if (do_pliku.bad()) {
    //   if (do_pliku.is_open()) do_pliku.close();
    //  return -2;
    //}
     if (do_pliku.is_open()) do_pliku.close();
    //if (do_pliku.fail()) return -3;
    return 0;
}

int Odczyt_Wydarzen(std::vector<Wydarzenie>* wydarzenia,Profil profil)
{
    int ilosc = 0;
    if (!wydarzenia->empty()) wydarzenia->clear();
    Wydarzenie temp;
    std::ifstream z_pliku;
    std::string sciezka;
    sciezka = "Events/";
    sciezka += profil.username;
    sciezka += "-events.event";
    z_pliku.open(sciezka.c_str(),std::ifstream::binary);
    //if(!z_pliku.is_open()) return -1;
    z_pliku.read((char*)&ilosc,sizeof(int));
    std::cout << ilosc << std::endl;
//  if (z_pliku.bad()) {
    //   if (z_pliku.is_open()) z_pliku.close();
    //  return -2;
    //}
    for (int i = 0; i < ilosc; ++i)
    {
        memset((void*)&temp,0,sizeof(Wydarzenie));
        z_pliku.read((char*)&temp,sizeof(Wydarzenie));
        wydarzenia->push_back(temp);
    }
    //if (z_pliku.bad()) {
    //   if (z_pliku.is_open()) z_pliku.close();
    //  return -2;
    //}
    if (z_pliku.is_open()) z_pliku.close();  
    return 0;
}

Chciałbym powiedzieć, że prawie cały czas czyszczę wektor i umieszczam w nim nowe wartości(będzie to zresztą zaraz widać):

void Zapisz_wydarzenie(GtkWidget* widget, gpointer data)
{
    Profil* dad = (Profil*) data;
    GtkTextIter poczatek;
    GtkTextIter koniec;
    gtk_text_buffer_get_bounds(GTK_TEXT_BUFFER(widok_bufor),&poczatek,&koniec);
    Wydarzenie temp;
    guint dzien,miesiac,rok;
    gtk_calendar_get_date(GTK_CALENDAR(Kalendarz),&rok,&miesiac,&dzien);
    temp.dzien = dzien;
    temp.godzina = atoi(gtk_entry_get_text(GTK_ENTRY(Entrys[1])));
    temp.ID = zbior_wydarzen.size();
    temp.miesiac = miesiac;
    temp.minuta = atoi(gtk_entry_get_text(GTK_ENTRY(Entrys[2])));
    temp.opis = gtk_text_buffer_get_text(GTK_TEXT_BUFFER(widok_bufor),&poczatek,&koniec,FALSE);
    std::cout << temp.opis << std::endl;
    temp.p_godzina = atoi(gtk_entry_get_text(GTK_ENTRY(Entrys[3])));
    temp.p_minuta = atoi(gtk_entry_get_text(GTK_ENTRY(Entrys[4])));
    temp.rok = rok;
    temp.tytul = gtk_entry_get_text(GTK_ENTRY(Entrys[0]));
    zbior_wydarzen.push_back(temp);
     Zapis_Wydarzen(zbior_wydarzen,*dad);
    PokazZdarzenia(Kalendarz,data);
}

Funkcja Pokaz_Zdarzenia:

void PokazZdarzenia(GtkWidget calendar, gpointer data)
{
Odczyt_Wydarzen(&zbior_wydarzen,
dane);
zbior_widgetow = Laduj_widgety(zbior_wydarzen);
for (unsigned i = 0; i < zbior_widgetow.size(); ++i)
{
if (zbior_wydarzen[i].dzien == dzien && zbior_wydarzen[i].miesiac+1 == miesiac && zbior_wydarzen[i].rok == rok)
{
gtk_box_pack_start(GTK_BOX(VboxScroll),zbior_widgetow[i].Event_Box,FALSE,FALSE,0);
g_signal_connect(G_OBJECT(zbior_widgetow[i].Event_Box), "button_press_event",G_CALLBACK(test_a),&zbior_widgetow[i]);
}
}
}

Funckja Laduj_widgety:

std::vector<NowyWidget> Laduj_widgety(std::vector<Wydarzenie> wydarzenia)
{
    std::vector<NowyWidget> all;
    NowyWidget temp;
    for (unsigned i = 0; i < zbior_wydarzen.size(); ++i)
    {
        temp = nowy_widget_init(zbior_wydarzen[i]);
        all.push_back(temp);
    }
    return all;
}

Kod zawsze wyrzuca się na samym końcu funkcji: OdczytWydarzen.

Kody są poskracane do tylko najważniejszych części żeby było łatwiej patrzeć. Wiem ,że kodu jest dużo i pewnie nie będzie Wam się chciało czytać, ale jeśli ktokolwiek znalazłby czas to był bym wdzięczny.

Z góry dziękuję.

0

Sprawa oczywista.

  • Odczyt_Wydarzen, linia 45: nie możesz "zerować" w ten sposób klas/struktur, jeśli wewnątrz masz pola bardziej złożonych typów, w tym przypadku klasa string. Zresztą, po co zerujesz tę strukturę, jeśli linię niżej i tak ją zapełniasz danymi z pliku?
  • Odczyt_Wydarzen, linia 46: podobnie jak wyżej - nie możesz czytać w ten sposób.
  • Zapis_Wydarzen, linia 15: j/w. - nie możesz zapisywać w ten sposób.

Odsyłam do tego tematu.

0

Dziękuję Ci bardzo za odpowiedź. Memset'a wywaliłem, ale nie rozumiem dlaczego nie mogę tak zapisywać/odczytywać?
Przeczytałem temat do którego podesłałeś link, ale wydaje mi się, że zapis dobrze robię. Najpierw ilość elementów zapisuję, a potem każdy element osobno?

Przy okazji stwierdziłem, że zapis i odczyt pliku za każdym razem jest głupim pomysłem i zapis dałem tylko przy zamknięciu programu, a odczyt przy włączaniu i teraz się nie wywala.

0

Jednak się wywala, proszę wytłumacz dlaczego nie mogę tak zapisywać elementów?

0

Aaa, czyli że muszę każdy element struktury osobno zapisać, a potem każdy element osobno odczytać i wpakować do struktury i na końcu do wektora? Tylko skąd będę wiedział jakiej długości jest string przy odczycie?

0
AAAA napisał(a)

Zacznijmy od struktur:


typedef struct{
std::string tytul,opis;
short int godzina,minuta,p_godzina,p_minuta,dzien,miesiac,rok,ID;
} Wydarzenie;

typedef struct{
std::string username,password,znak_zodiaku,miasto,horoskop;
int dzien_urodznia, miesiac_urodzenia, rok_urodzenia;
Pogoda pogoda;
Biorytm biorytm;
} Profil;

typedef struct{
std::string kawalek_opisu;
short int ID;
GtkWidget Labels[4];
GtkWidget
Vbox;
GtkWidget Hboxs[2];
GtkWidget
Event_Box;
} NowyWidget;



nie mozesz tak zapisywac tych struktur powyzej, poniewaz nie sa one "POD"ami.
POD = http://www.parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.7

w skrocie, spojrz na przyklad na "wydarzenie".
kupa intów - ok.
o short-int wiesz, sa to ~dwa bajty, żywy numeryk jak z rejestru, wiec mozesz sobie go binarnie zrzucic.
ale, o, jest jeszcze std::string.
czy wiesz jaki uklad bajtow/bitow ma "string" w srodku?
czy string to po prostu tablica bajtow? jesli tak sadzisz, objerzyj plik .h/.hpp/.cpp ktory deklaruje/definiuje te klase, pewnie sie zdziwisz ze to nie taka tylko tablica char[]..

jezeli masz cokolwiek co jakkolwiek posiada w sobie wskaznik albo referencje, to jezeli nie jestes "niesamowitym specjalista", to nie mozesz sobie tego ot tak sobie zrzucac na dysk jako tablice bajtow. chocby z tego glupiego powodu, ze jezeli zapiszesz w ten sposob WARTOSC wskaznika/referencji, czyli adres ktore one pamietaja, to potem jak program odpalisz za dwa dni, to system temu wskaznikowi/referencji przydzielilby inny adres. musisz znalazc sposob na zapisanie 'tresci wskazywanej przez wskaznik/referencje' a nie na zapisanie 'wartosci wskaznika'. niestety, z braku czasu, łatwiej Ci tego teraz nie wyjasnię..
0
AAAA napisał(a)

Aaa, czyli że muszę każdy element struktury osobno zapisać, a potem każdy element osobno odczytać i wpakować do struktury i na końcu do wektora? Tylko skąd będę wiedział jakiej długości jest string przy odczycie?

banalne: nie będziesz wiedział. dlugość też musisz sobie zapisać, albo wymyslic sprytny sposob na "wiedzenie" że string sie konczy właśnie tam a nie gdzieś indziej. najbezpieczniejsze i najnormalniejsze jest po prostu zapisanie sobie najpierw dlugosci a zaraz potem serii znakow, pseudokod

napis = "asldjasldada";

size_t dlugosc = strlen(napis) // napis.size(), etc..
write( & dlugosc, sizeof(dlugosc) )
write( napis, dlugosc)

...

size_t dlugosc;
read ( & dlugosc, sizeof(dlugosc) );
char* blah = new char[dlugosc];
read (blah, dlugosc);

0

Właśnie po napisaniu posta pomyślałem, że najpierw zapiszę wszystkie długości stringów, odczytam je i na ich podstawie odczytam potem resztę. Zaraz sie za to zabiorę czy w metodzie write muszę zamieniać stringa na char* ?

0

Tak. Metoda c_str jest od tego.

0

Dziękuję Wam bardzo za odpowiedzi na moje pytania(które raczej to trudnych nie należały ; p ). Zaraz zmienię kod i przetestuje.

1 użytkowników online, w tym zalogowanych: 0, gości: 1, botów: 0