fstream - czytanie pierwszej i drugiej linii nie działa?

0

Napisałem funkcję, która spisuje mi kolejne linie pliku do tablicy typu const char *. Gdy z niej wczytuję wartości świeżo po dodaniu, wyświetla mi je bez problemu, jednak przy pobieraniu tych wartości z innej funkcji, pierwsza i druga dodana linia jest pusta.
To, co mam w konsoli:

Getting level names:
Check level/0.ofl: OK
subline 0: Test
subline 1: test2

subline 2: first.pcx
subline 3: nomini.pcx
Check level/1.ofl: not present, stop checking.
level 0:
(tu podlinia 0 pusta)
(tu podlinia 1 pusta)

firstmini.pcx
nomini.pcx
end of level 0

Found 1 level(s)

Funkcja czytająca plik(i):

int getlevelcount() {
cout<<endl<<"Getting level names:"<<endl;
    int c = 0;
    int d = 0;
	int line = 0;
    char strch[15];
	FILE *lvfile;
	FILE *lvfile2;
    while(d == 0) {
        sprintf(strch, "level/%d.ofl", c);
		cout<<"Check "<<strch<<": ";
		lvfile = fopen(strch, "r");
        if(lvfile) {
			fclose(lvfile);
			cout<<"OK"<<endl;
			fstream loadl;
			loadl.open(strch);
			string ltmp = "";
			line = 0;
			while(loadl) {
				if(line < 4) {
					loadl>>ltmp;
					if(line == 0) levele[c][0] = ltmp.c_str(); else
					if(line == 1) levele[c][1] = ltmp.c_str(); else
					if(line == 2) levele[c][2] = ltmp.c_str(); else
					if(line == 3) {
						lvfile2 = fopen(ltmp.c_str(), "r");
						if(lvfile2) { levele[c][3] = ltmp.c_str(); fclose(lvfile2); } else levele[c][3] = nomini;
					}
					cout<<"subline "<<line<<": "<<levele[c][line]<<endl;
					line++;
				} else break;
			}
			c++;
		} else { cout<<"not present, stop checking."<<endl; d = 1; }
    }
	if(c == 0) { MessageBoxA(NULL, "Didn't find any level files!", gname, 0); Sleep(100); exit(0); }
	lvcount = c;
	return c;
}

Oraz funkcja umieszczona niżej w kodzie, czytająca te wartości (właśnie tutaj nie widać pierwszych dwóch linii):

int selectlevel() {
    clear_to_color(screen, makecol(0, 0, 0));
    BITMAP *logo = NULL;
	FONT *opis = NULL;
	BITMAP *mini = NULL; // 350x200
	opis = load_font("tinyfont.pcx", default_palette, NULL);
	bool pushed = false;
	int lvpos = 1;
	cout<<"current level position: "<<lvpos<<endl<<endl;
	logo = create_bitmap(640, 480);
	mini = create_bitmap(350, 200);
	mini = load_pcx(levele[lvpos][3], default_palette);
	if(!(logo = load_pcx("clear.pcx", default_palette))) { cout<<"There is no \"clear\" file!"; Sleep(2000); exit(0); }
	while(true) {
		clear_keybuf();
		if(!key[KEY_LEFT] && !key[KEY_RIGHT] && !key[KEY_ENTER] && pushed == true) pushed = false;
		blit(logo, buffer, 0, 0, 0, 0, 640, 480);
		blit(mini, buffer, 0, 0, 145, 186, 350, 200);
		textprintf_centre_ex(buffer, opis, SCREEN_W/2, 410, makecol(255, 255, 255), -1, levele[lvpos][0]);
		textprintf_centre_ex(buffer, opis, SCREEN_W/2, 425, makecol(255, 255, 255), -1, levele[lvpos][1]);
		
		if(key[KEY_LEFT] && pushed == false) {
			pushed = true;
			if(lvpos == 1) lvpos = lvcount; else lvpos--;
			mini = load_pcx(levele[lvpos][3], default_palette);
	cout<<"current level position: "<<lvpos<<endl;
		}
		if(key[KEY_RIGHT] && pushed == false) {
			pushed = true;
			if(lvpos == lvcount) lvpos = 1; else lvpos++;
			mini = load_pcx(levele[lvpos][3], default_palette);
	cout<<"current level position: "<<lvpos<<endl;
		}
		if(key[KEY_ESC] && pushed == false) {
			pushed = true;
			return -1;
		}
		blit(buffer, screen, 0, 0, 0, 0, 640, 480);
	}
    destroy_bitmap(logo);
    destroy_bitmap(mini);
}

Wartości są zapisywane, później odczytywane z tablicy zapisanej w ten sposób (znajduje się w kodzie wcześniej, niż jakiekolwiek funkcje):

const char *levele[1000][5] = {{"", "", "", ""}};

Cały kod się kompiluje, jednak przy ładowaniu funkcji selectlevel(); aplikacja wysypuje się ("Program [...] przestał działać.").
Co należy poprawić, by były czytane dwie pierwsze linie (dwa pierwsze elementy tablicy)?

0
  1. zmiłuj się z tym formatowaniem kodu (nie jest bardzo źle, ale mogło by być dużo lepiej).
  2. po co fopen(strch, "r"); jeśli i tak używasz strumieni STL?
  3. ładowanie czegokolwiek do const to już wielki błąd.
  4. jeśli miałbym zgadywać co jest źle to to (całości kodu nie analizuje bu mnie zbyt męczy):
char levele[10][5][1000] = {{"", "", "", ""}};
10 - bo tam była za duża liczba, a level'i masz tylko parę
5 - bo tak już było
1000 - bo nie wiem co wczytujesz zakładam, że coś dużego
  1. za dużo masz komunikacji przez zmienne globalne, zdajesz sobie sprawę, że jest coś takiego jak argument funkcji!
Tojtek napisał(a)
if(line == 0) levele[c][0] = ltmp.c_str(); else
if(line == 1) levele[c][1] = ltmp.c_str(); else
if(line == 2) levele[c][2] = ltmp.c_str(); else

Słyszałeś o pętlach i tablicach? Najwyraźniej tak, ale masz pojęcie po co są?

levele[c][line] = ltmp.c_str();

PS. W sumie jak już używasz angielskiego w kodzie, to lepiej by było stosować odmianę angielską a nie polską: levele powinno być levels

0
  1. Przyzwyczajenie, wiem, że złe.
  2. Czyli powinienem sprawdzać istnienie pliku w stylu if(loadl.open("jakisplik"))?
  3. I tu jest problem, bo gdy zmienię te const char * na chociażby string, mam wyrzuconą masę błędów z load_pcx, które wymaga const char *. Czy powinienem przy ładowaniu zmieniać const char * na string?
  4. Gdy zmieniam na to, co podałeś, mam błędy tego typu:
    main.cpp:62:89: error: incompatible types in assignment of 'const char*' to 'char [5]'
    Czyli tam, gdzie mam zamianę ze zmiennej typu string, na const char * (.c_str()) - a gdy usunę .c_str(), wychodzą kombinacje, które w efekcie dają masę błędów.
  5. Tak, najwidoczniej namieszałem. :/ Dałem po to zmienną globalną, by mieć dostęp do niej z każdej funkcji, a takich będzie chyba 3.
  6. Słyszałem i mam pojęcie. Takie if'y dałem, by sprawdzić, czy będzie jakaś różnica. - Poprawione, z powrotem.

Co do zmiennej 'levele', ma ona zawierać do 1000 pozycji (no, ew. 100), każda z tych pozycji ma mieć 4 pola: nazwa, autor, nazwa pierwszego pliku, nazwa drugiego pliku. Pola te są wypełniane (jednak nie do końca, jak widać) właśnie funkcją getlevelcount();.

Ad. P.S.: Wiem o tym, zmienię to.

0

ok nie załapałem co robi to load_pcx.
Ale teraz już wiem na 100% w czym problem:
masz zmienną lokalną ltmp, która jest std::string. Ta klasa sama zarządza pamięcią potrzebną na przechowanie napisu. Natomiast ty pobierasz napis w postaci wskaźnika na C-string i przypisujesz to do zmiennej globalnej. W momencie gdy zmienna ltmp traci ważność sprząta ona po sobie pamięć, w efekcie twoje wskaźniki wskazują na zupełnie złe miejsce.

Jak poprawić?
Zamień tą globalną tablicę na std::string levels[1000][5]; a wszędzie tam gdzie potrzebujesz C-stringi użyj levels[x][y].c_str().

0

MarekR22, powiem Tobie tyle: jesteś wielki. Dziękuję za pomoc. :)

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