Błąd przy odczytywaniu z pliku do klasy

Błąd przy odczytywaniu z pliku do klasy
VE
  • Rejestracja:około 11 lat
  • Ostatnio:prawie 11 lat
  • Postów:8
0

Witam!
Piszę program Quiz w C++, mój program posiada klasę nadrzędną quiz oraz klasę potomną Category
Zasada działania programu jest taka że, kategoria pobiera i przechowuje pytania pobrane z odpowiedniego dla niej pliku np. Kategoria wojskowość pobiera i przechowuje dane z pliku wojskowosc.txt. Pytania przechowywane są w strukturze.

struct pytanie
{
string pyt;
string odp[4];
string dobraOdp;
};

oto interfejs:

#include<iostream>
#include<cstring>
#include<conio.h>
#include<cstdlib>
#include<ctime>
#include<vector>
#include<fstream>
using namespace std;

struct pytanie
{
string pyt;
string odp[4];
string dobraOdp;
};

class Quiz
{
private:
char* nazwa;
public:
Quiz(){nazwa= new char[strlen("BRAK")+1]; strcpy(nazwa,"BRAK");};
Quiz(char* nazwa){this->nazwa= new char[strlen(nazwa)+1]; strcpy(this->nazwa,nazwa);};
virtual ~Quiz(){delete[]nazwa;};
virtual void wypisz(){cout<<"Kategoria: "<<nazwa<<endl;};
};

class Category: public Quiz
{
private:

ifstream plik;
char *npliku;
pytanie *question;/** Wskaznik na strukture pytanie**/
vector<pytanie> t;

public:
void pobierz(ifstream & plik);
void wypStruct();
Category();

Category(char* n,char* npliku):Quiz(n)
{
    this->npliku=new char[strlen(npliku)+1];
    strcpy(this->npliku,npliku);

    plik.open(npliku,ios::in);
    if(plik.fail())
    {
    cout<<"NIe udalo sie nawiazac polaczenia z plikiem "<<npliku<<".\nProgram zostanie zamkniety.\n";
    exit(1);
    }

    pobierz(plik);

    plik.close();
}
~Category();

void wypisz();

};

A tutaj Definicje:

#include<iostream>
#include<cstring>
#include<conio.h>
#include<cstdlib>
#include<ctime>
#include<vector>
#include<fstream>
#include"q.h"
using namespace std;

Category::Category(){};

Category::~Category()
{
delete [] npliku;
cout<<"Usunieto obiekta.\n";
}

void Category::pobierz(ifstream & plik)
{
while(!plik.eof())
{
getline(plik,question->pyt);
cout<<question->pyt<<endl;

  for(int i=0;i<4;i++)
  {
    getline(plik,question->odp[i]);
    cout<<question->odp[i]<<endl;
  }

   getline(plik,question->dobraOdp);
   cout<<question->dobraOdp;

   t.push_back(*question);
  }

}

void Category::wypStruct()
{
cout<<question->pyt<<endl<<endl;

for(int i=0;i<4;i++)
{
    cout<<question->odp[i]<<" ";
    if(i==1)cout<<endl;
}

}

void Category::wypisz()
{
Quiz::wypisz();

for(int i=0; i<t.size();i++)
{
    wypStruct();
}

}

Jak można zauważyć używam klasy Vector do przechowywania pytań, wiem że nie jest to najefektywniejsze rozwiązanie ale zwyczajnie jest ono najwygodniejsze bo nie muszę zliczać wierszy które pobieram... Ponad to moja struktura ma przechowywać wszystkie informacje i dane dotyczące pytania, z pytaniem i odpowiedziami włącznie.

Mam kilka wątpliwości:

  1. Co do tablicy (wektora) struktur, która docelowo ma przechowywać pytania.
    Tzn. skoro mam strukture o nazwie pytanie to deklaracja wektora to vector<pytanie>t ? czy vector<struct>t?
    Kompilator przepuszcza mi tylko tą pierwszą wersje i wydaje się ona dobra ze względu na to że przechowuje dane które mają wyglądać jak moja utworzona struktura.

  2. Nie mogę się odwołać do struktury w ten sposób np pushback(plik,pytanie.odp);
    Więc utworzyłem wskaźnik na strukturę i umieściłem go w klasie: pytanie *question; Dzięki temu już mogę się odwoływać do mojej struktury.
    Tylko nie wiem czy jest to dobre rozwiązanie.

No i teraz najważniejsze, w sumie główny powód mojego postu tutaj jest fakt, że program wywala się przy pobieraniu zmiennych

domyślam się że chodzi tutaj o linijkę pushback(plik,*quiz);
Generalnie pobieranie danych z pliku realizuje za pomocą tej metody:

void Category::pobierz(ifstream & plik)
{
while(!plik.eof())
{
getline(plik,question->pyt);
cout<<question->pyt<<endl;

  for(int i=0;i<4;i++)
  {
    getline(plik,question->odp[i]);
    cout<<question->odp[i]<<endl;
  }

   getline(plik,question->dobraOdp);
   cout<<question->dobraOdp;

   t.push_back(*question);
  }

}

i wiem że to ona wywala mi cały program, niestety nie wiem dla czego. Czy mógłby mi ktoś z kolegów zobaczyć w czym leży problem i napisać jak go rozwiązać?

Pozdrawiam i z góry dziękuję za pomoc.

Dodam jeszcze załącznik rar z plikami klasy oraz plikiem wejściowym.

szweszwe
Sformatuj kod. Pokaż może maina i zawartość pliku. Masz Pastebin, możesz tam wrzucić.
VE
  • Rejestracja:około 11 lat
  • Ostatnio:prawie 11 lat
  • Postów:8
0

Udostępnione:D
jak cos to tutaj jest link:

http://4programmers.net/Pastebin/2912

kq
Moderator C/C++
  • Rejestracja:prawie 12 lat
  • Ostatnio:dzień
  • Lokalizacja:Szczecin
1

Dlaczego nie używasz std::string? Obecnie Twój quiz nie jest bezpieczny w użyciu i nie respektuje zasady trzech (ew. 5 lub 0).

Nigdzie nie tworzysz struktury dla wskaźnika question ⟶ dokonujesz dereferencji niezainicjalizowanego wskaźnika ⟶ UB. W ogóle nie ma sensu aby była to zmienna klasy, lokalnie w funkcji wczytującej dodaj.

Dlaczego funkcja wypisz nie wypisuje elementów (elementu?) wektora?


VE
  • Rejestracja:około 11 lat
  • Ostatnio:prawie 11 lat
  • Postów:8
0
kq napisał(a):

Dlaczego nie używasz std::string? Obecnie Twój quiz nie jest bezpieczny w użyciu i nie respektuje zasady trzech (ew. 5 lub 0).

Ponieważ używam biblioteki <cstring> ale zmieniłem na string.

Nigdzie nie tworzysz struktury dla wskaźnika question ⟶ dokonujesz dereferencji niezainicjalizowanego wskaźnika ⟶ UB. W ogóle nie ma sensu aby była to zmienna klasy, lokalnie w funkcji wczytującej dodaj.

Po zmianie którą zaproponowałeś, tzn strukturę wyrzuciłem z listy zmiennych klasy i utworzyłem nową w funkcji pobierającej

Kopiuj

/**Funkcja pobierająca dane z pliku**/

void Category::pobierz(ifstream & plik)
{
    pytanie *question= new pytanie;/**Tworzenie nowego elementu na podstawie struktury**/

    while(!plik.eof())
    {
      getline(plik,question->pyt);
      cout<<question->pyt<<endl;

      for(int i=0;i<4;i++)
      {
        getline(plik,question->odp[i]);
        cout<<question->odp[i]<<endl;
      }

       getline(plik,question->dobraOdp);
       cout<<question->dobraOdp;

       t.push_back(question);
      }
}

Dlaczego funkcja wypisz nie wypisuje elementów (elementu?) wektora?

Okey, masz racje. Nie wiem co mi się uroiło że tak to zrobiłem:P Tutaj jest poprawiona wersja:)

Kopiuj
void Category::wypisz()
{
    //pytanie question;

    Quiz::wypisz();

    cout<<t.size()<<endl;/**Sprawdzam dla samego siebie czy mój wektor wogóle posiada jakąś wielkość i elementy**/

    for(int i=0; i<t.size();i++)
    {
        cout<<t[i].pyt<<endl<<endl;

        for(int i=0;i<4;i++)
        {
        cout<<t[i].odp[i]<<" ";
        if(i==1)cout<<endl;
        }
    }
}

Teraz mi program wypisuje pytanie jednak niestety oto efekt działania programu. Screena przekazuje w załączniku.

edytowany 1x, ostatnio: Vesper
szweszwe
  • Rejestracja:ponad 11 lat
  • Ostatnio:5 dni
  • Lokalizacja:Kraków
  • Postów:1694
1

Przy wypisywaniu zamień wewnętrznego fora z i np na j bo wypisujesz nie to co chcesz. Poza tym wartość size'a jest 2 a z pliku teoretycznie wczytujesz 1 pytanie.

VE
  • Rejestracja:około 11 lat
  • Ostatnio:prawie 11 lat
  • Postów:8
0

Okey, wielkie dzięki:) Nie zauważyłem tego:)

Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)