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.

0
string s("Ala ma kota");
len=s.length();
plik.write(s.c_str(),len);

To o czym wspomniał quetzalcoatl ale bez pseudokodu 'sprytny sposób na "wiedzenie" że string się kończy właśnie tam a nie gdzieś indziej':
zapis:

string s("Ala ma kota");
plik.write(s.c_str(),s.length()+1);

odczyt:

string s;
getline(plik,s,0);
0

Kod zmieniłem i wydaję się, ze wszystko działa bez problemu. Chciałbym Wam bardzo podziękować.

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