Wczytanie tekstu z pliku do tablicy

Wczytanie tekstu z pliku do tablicy
KA
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 7 lat
  • Postów:18
0

Witajcie. Piszę aplikację quiz. W sumie mam ją już ukończoną, ale bardzo amatorsko. Aplikacja napisana jest w C++ Builder. Chodzi mi o wczytywanie pytań i odpowiedzi do programu. Aktualnie wykonuje to tak:

Kopiuj
void __fastcall TForm1::Wczytaj()
{
       fstream plik;
       plik.open("pyt.txt", ios::in);

       if(plik.good() == false)
       {
              ShowMessage("Błąd! Nie udało się wczytac pliku!");
              exit(0);
       }


       int nr_linii = (nr_pytania - 1) * 5 + 1;
       int aktualny_nr = 1;

       while(getline (plik, Linia))
       {
              if(aktualny_nr == nr_linii) Tresc = Linia;
              if(aktualny_nr == nr_linii + 1) A = Linia;
              if(aktualny_nr == nr_linii + 2) B = Linia;
              if(aktualny_nr == nr_linii + 3) C = Linia;
              if(aktualny_nr == nr_linii + 4) Poprawna = Linia;
              aktualny_nr++;
       }
       plik.close();
       Wypisz();
}

screenshot-20171109202001.png

Czyli za każdym kliknięciem przycisku "Następne" wykonuje się ponownie wczytanie danych z pliku. Ja chcę, aby to zrobić tak, że w aplikacji użytkownik sam wskazuje plik, który ma zostać wczytany i wczytuje go do tablicy całościowo od razu. Czy jest taka możliwość?

C6
Metoda plik.good() zwraca boola to po co to porównanie?
KA
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 7 lat
  • Postów:18
0

Klasa TForm2

Kopiuj
class TForm2 : public TForm
{
     __published:

     public:
       string Linia, Tresc, A, B, C, Poprawna, Odpowiedz;
       int nr_pytania, punkt, czas;
       vector < string > tab;

       void __fastcall Wczytaj(); 
       void __fastcall Wypisz(int nr); 
       void __fastcall Sprawdz();  
       void __fastcall Zapisz(); 
       void __fastcall LiczCzas();

       __fastcall TForm2();

};
Kopiuj
void __fastcall TForm2::Wczytaj()
{
       if (Form1 -> OpenDialog1 -> Execute())
        {
                ifstream plik (Form1 -> OpenDialog1 -> FileName.c_str());
                if (plik.good() == false)
                {
                        ShowMessage("Błąd. Wskaż prawidłowy plik!");
                }
                else {
                        while (getline(plik, Linia)) tab.push_back(Linia);
                        plik.close();
                        Form1 -> Tekst_BladNazwisko -> Caption = "Plik wczytano poprawnie!";
                        Form1 -> Przycisk_Start -> Enabled = true;
                }
                
        }
}

W Form1 mam wszystkie przyciski itp. (elementy wizualne)
Po skompilowaniu programu, wczytaniu pliku wywala błąd:
Bez tytułu.jpg

i otwiera się debugger z podświetloną tą linijką:

Kopiuj
  bool empty() const { return this->_M_start == this->_M_finish; }   

Zauważyłem, że jeżeli jest wszystko w jednej klasie to nie ma żadnych problemów!

edytowany 1x, ostatnio: Karpiusz
06
Dlaczego Linia jest polem klasy zamiast być zmienną lokalną?
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
0

Zgaduję, że odwołujesz się do tab w chwili, gdy obiekt klasy TForm2 już nie istnieje.

KA
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 7 lat
  • Postów:18
0
0x666 napisał(a):

Zgaduję, że odwołujesz się do tab w chwili, gdy obiekt klasy TForm2 już nie istnieje.

Dlaczego miałby przestać istnieć?

06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
0

Jak pisałem - zgaduje ;) Z kodu, który podałeś, niewiele da się wyciągnąć, jeśli chodzi o przyczynę błędu.

W Form1 mam wszystkie przyciski itp. (elementy wizualne)

Jeśli TForm1 jest główną formą, czym jest TForm2? Samo wywołanie TForm2::Wczytaj() powoduje błąd? Jak tworzysz obiekt klasy TForm2?

KA
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 7 lat
  • Postów:18
0
0x666 napisał(a):

Jak pisałem - zgaduje ;) Z kodu, który podałeś, niewiele da się wyciągnąć, jeśli chodzi o przyczynę błędu.

W Form1 mam wszystkie przyciski itp. (elementy wizualne)

Jeśli TForm1 jest główną formą, czym jest TForm2? Samo wywołanie TForm2::Wczytaj() powoduje błąd? Jak tworzysz obiekt klasy TForm2?

https://pastebin.com/059ZUtRw

Błąd powoduje prawdopodobnie ta linijka:

Kopiuj
while (getline(plik, Linia)) tab.push_back(Linia);

Ale nie było z nią problemów kiedy istniała tylko jedna klasa.

06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
0

Ta linia jest jak najbardziej ok. Nie widzę, żeby Form2 było tworzone (cały czas upieram się, że obiekt klasy TForm2 nie istnieje w czasie wywołania metody). Sprawdź, jaka jest wartość wskaźnika this wewnątrz TForm2::Wczytaj().

Jaki jest sens klasy TForm2, jeśli wszędzie odwołujesz się do Form1?

KA
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 7 lat
  • Postów:18
0
0x666 napisał(a):

Ta linia jest jak najbardziej ok. Nie widzę, żeby Form2 było tworzone (cały czas upieram się, że obiekt klasy TForm2 nie istnieje w czasie wywołania metody). Sprawdź, jaka jest wartość wskaźnika this wewnątrz TForm2::Wczytaj().

Jaki jest sens klasy TForm2, jeśli wszędzie odwołujesz się do Form1?

Więc jak stworzyć Form2?
Co do sensu klasy TForm2. Robię projekt na uczelnie. Kazał jak najwięcej klas, a nie wiem jak to zrobić bardziej estetyczniej. Oczywiście klasę TForm2 podziele jeszcze na dwie inne. na razie walczę z tym błędem.

06
Sprawdziłeś ten this?
MarekR22
Moderator C/C++
  • Rejestracja:ponad 17 lat
  • Ostatnio:2 minuty
0

Po pierwsze napisz nową klasę opisującą pytania.
Zgodnie z wzorcem MVC (Model View Controller), masz napisać klasę modelu danych, który przechowuje te dane.
TForm1 to twój kontroler, a widokiem są elementy UI-a, które wyklikałeś.

I jeszcze: https://4programmers.net/Forum/C_i_C++/300163-pytanie_o_strukture_danych_w_pliku_txt?p=1422976#id1422976 (pewnie kolega).


Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 2x, ostatnio: MarekR22
KA
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 7 lat
  • Postów:18
0
MarekR22 napisał(a):

Po pierwsze napisz nową klasę opisującą pytania.

Ale to mi nic nie da, bo i tak muszę się odwołać do TForm1, aby wskazać OpenDialog1.

Jak sprawdzić ten this?

MarekR22
a kto ci karze otwierać dialog w nowej klasie? Tam przekazujesz tylko strumień, albo nazwę pliku.
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
0

Jak sprawdzić ten this?

Debuggerem, albo nawet massageboxem (wyświetlasz zawartość AnsiString().sprintf("%p", this)).

aby wskazać OpenDialog1.

A po co? W onclicku przycisku odpalasz dialoga i ścieżkę podajesz w parametrze metody wczytaj().

KA
  • Rejestracja:ponad 12 lat
  • Ostatnio:około 7 lat
  • Postów:18
0

W ogóle nie rozumiem co wy do mnie mówicie. :|
To musi być coś popierdzielone z tymi klasami, ponieważ wkleiłem to do pierwszej klasy TForm1

Kopiuj
void __fastcall TForm1::Przycisk_WczytajClick(TObject *Sender)
{
        string Linia;
        if (OpenDialog1 -> Execute())
        {
                ifstream plik (OpenDialog1 -> FileName.c_str());
                if (plik.good() == false)
                {
                        ShowMessage("Błąd. Wskaż prawidłowy plik!");
                }
                else {
                        while (getline(plik, Linia)) tab.push_back(Linia);
                        plik.close();
                        Tekst_BladNazwisko -> Caption = "Plik wczytano poprawnie!";
                        Przycisk_Start -> Enabled = true;
                }
        }
}

oraz w publicu klasy dodałem

Kopiuj
vector < string > tab;

I wczytało plik bez żadnych problemów...

Ale ja chcę mieć wczytywanie w drugiej klasie, a w tej same przyciski...

MarekR22
Moderator C/C++
  • Rejestracja:ponad 17 lat
  • Ostatnio:2 minuty
0
Karpiusz napisał(a):

Po skompilowaniu programu, wczytaniu pliku wywala błąd:
Bez tytułu.jpg

i otwiera się debugger z podświetloną tą linijką:

Kopiuj
  bool empty() const { return this->_M_start == this->_M_finish; }   

Zauważyłem, że jeżeli jest wszystko w jednej klasie to nie ma żadnych problemów!

To jest linijka z STL-a. Żeby ustalić co jest nie tak, to:

  1. Odtwórz crash
  2. jak debugger zatrzyma się na tej linijce, rozejrzyj się po UI IDE, powinieneś znaleźć widok "Call stack"
  3. "Call stack" zawiera listę funkcji, które wywołały bieżącą funkcję
  4. Klikaj kolejne pozycje, aż osiągniesz swój kod.
  5. Podejrzyj zmienne w okolicach swojego kodu i zastanów, się czy jakiś wskaźnik nie wskazuje na nieprawidłową wartość.

Jeśli chcesz pomocy, NIE pisz na priva, ale zadaj dobre pytanie na forum.
edytowany 1x, ostatnio: MarekR22
06
  • Rejestracja:prawie 20 lat
  • Ostatnio:około rok
  • Postów:2440
0

Inaczej. Ustaw breakpointa na linii Form2 -> Wczytaj();, wywołaj zdarzenie z tą linią i kiedy program zatrzyma się na niej, podejrzyj, jaką wartość ma wskaźnik Form2.

I wczytało plik bez żadnych problemów...

Dlatego że obiekt tej klasy istnieje w pamięci, a obiekt wskazywany przez wskaźnik Form2 najprawdopodobniej nie. Sprawdź ten wskaźnik...

RE
  • Rejestracja:ponad 18 lat
  • Ostatnio:około 16 godzin
0

Kolego jak wyżej koledzy wspomnieli o MVC. Poczytaj o tym wzorcu są przykłady na necie. To jedno
Napisz testy jednostkowe w gtest(gmock) do softu. Unikniesz pewnych problemów. Wpisz w google TDD gtest.


We are the 4p. Existence, as you know it, is over. We will add your biological and technological distinctiveness to our own. Resistance is futile

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.