• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Projekt - problem z wieksza iloscia pytan

Cloud VPS
0 głosów
727 wizyt
pytanie zadane 3 stycznia 2019 w C i C++ przez kamasazi98 Początkujący (410 p.)

Witam. 
W szkole zadali nam ciutę większe zadanie żeby zrobić projekt na około 75 pytań. Program napisałem i działa, lecz pomyślałem, że sprawdzę czy aby na pewno jest sprawny gdy dam maksymalną ilość pytań i tu pojawia się właśnie problem. Konsola po prostu wywala błąd i kończy program. Kompilator nie wyrzuca żadnych błędów, a ja nie mam bladego pojęcia co może być tego przyczyną, dlatego zwracam się do Was. 

 

#include <iostream>
#include <string>
#include <windows.h>
#include <fstream>
#include <ctime>
#include<algorithm>
#include<iomanip>
using namespace std;
int x=75; //ilosc pytan
int n,nr_pytania=0,nr_linii=1, wylosowanych=0,punkty=0;
string linia;
struct pytania{
    string pytanie;
    string odpowiedzA;
    string odpowiedzB;
    string odpowiedzC;
    string odpowiedzD;
    string poprawna;
    string odpowiedz_uzytkownika;
};
void sprawdz_pytania(int n);
void wprowadzenie(int x);
void wpisz_do_bazy(pytania *baza, int nr_pytania, int nr_linii, string linia);
void losuj_pytanie(int n, int nr_pytania,int wylosowanych, int *czy_wylosowane,int *numery_pytan,int x);
void wypelnij_0_czy_wylosowane(int *czy_wylosowane, int *numery_pytan_zlych,int x);
bool powtorzona(int *czy_wylosowane,int nr_pytania);
void pytanie(pytania *baza, int n,int *numery_pytan,int &punkty,int *numery_pytan_zlych);
void wynik(int n, int punkty);
void bledne_odp(int *numery_pytan_zlych,pytania *baza,int x);
int main()
{

    wprowadzenie(x);
    cout<<"Na ile pytan chcesz odpowiadac z zakresu (0;75>?"<<endl;
    cin>>n;
    sprawdz_pytania(n);
    int *czy_wylosowane=new int[x];
    int *numery_pytan=new int [x];
    int *numery_pytan_zlych=new int [x];
    pytania *baza=new pytania[x];
    wypelnij_0_czy_wylosowane(czy_wylosowane,numery_pytan_zlych,x);
    losuj_pytanie(n,nr_pytania,wylosowanych,czy_wylosowane,numery_pytan,x);
    wpisz_do_bazy(baza,nr_pytania,nr_linii,linia);
    system ("cls");
    pytanie(baza,n,numery_pytan,punkty,numery_pytan_zlych);
    system("cls");
    wynik(n,punkty);
    bledne_odp(numery_pytan_zlych,baza,x);

delete [] numery_pytan_zlych;
delete [] czy_wylosowane;
delete [] numery_pytan;
delete [] baza;
    return 0;
}
void sprawdz_pytania(int n)
{
    if(n<0 || n>75)
    {
        cout<<"Podana liczba nie miesci sie w zakresie";
       Sleep(1000);
        exit(0);
    }
}
void wprowadzenie(int x)
{
cout<<"Witaj w quizie o historii Polski. Maksymalnie jest "<<x<<" pytan, sam ustalasz na ile chcialbys odpowiedziec. Powodzenia!"<<endl<<endl;
Sleep(1000);

}
void wpisz_do_bazy(pytania *baza, int nr_pytania, int nr_linii, string linia)
{
    fstream plik;
    plik.open("quiz.txt",ios::in);

    if (plik.good()==false)
    {
        cout<<"Nie udalo sie otworzyc pliku!";
        exit(0);
    }

    while(getline(plik,linia))
    {
        switch(nr_linii)
        {

            case 1: baza[nr_pytania].pytanie = linia;            break;
            case 2: baza[nr_pytania].odpowiedzA  = linia;        break;
            case 3: baza[nr_pytania].odpowiedzB  = linia;        break;
            case 4: baza[nr_pytania].odpowiedzC  = linia;        break;
            case 5: baza[nr_pytania].odpowiedzD  = linia;        break;
            case 6: baza[nr_pytania].poprawna  = linia;          break;
        }

        if (nr_linii==6) {nr_linii=0; nr_pytania++;}
        nr_linii++;
    }

    plik.close();
}
void losuj_pytanie(int n, int nr_pytania,int wylosowanych, int *czy_wylosowane, int *numery_pytan,int x)
{
    srand(time(0));
for(int i=0; wylosowanych<n;i++)
{

            int numerPytania;
            numerPytania = rand()%x;
    if(powtorzona(czy_wylosowane,numerPytania)==0)
    {
        numery_pytan[i]=numerPytania;
        wylosowanych++;
    }

}
}
void wypelnij_0_czy_wylosowane(int *czy_wylosowane,int *numery_pytan_zlych,int x)
{
    for(int i=0;i<x;i++)
        {
            czy_wylosowane[i]=0;
            numery_pytan_zlych[i]=0;
        }
}
bool powtorzona(int *czy_wylosowane,int numerPytania)
{
    if(czy_wylosowane[numerPytania]==1)
        return 1;
    else
    {
        czy_wylosowane[numerPytania]=1;
        return 0;
    }
}
void pytanie(pytania *baza, int n,int *numery_pytan,int &punkty,int *numery_pytan_zlych)
{
    int pomoc;
    for(int i=0;i<n;i++)
    {
        pomoc=numery_pytan[i];
       cout<<"***PYTANIE "<<i+1<<" na "<<n<<"***"<<endl<<endl;
       cout<<baza[pomoc].pytanie<<endl;
       cout<<"A. "<<baza[pomoc].odpowiedzA<<endl;
       cout<<"B. "<<baza[pomoc].odpowiedzB<<endl;
       cout<<"C. "<<baza[pomoc].odpowiedzC<<endl;
       cout<<"D. "<<baza[pomoc].odpowiedzD<<endl;
       cout<<endl;
       cout<<"Twoja odpowiedz to: ";
       cin>>baza[pomoc].odpowiedz_uzytkownika;
       cout<<endl;
       transform(baza[pomoc].odpowiedz_uzytkownika.begin(), baza[pomoc].odpowiedz_uzytkownika.end(), baza[pomoc].odpowiedz_uzytkownika.begin(), ::tolower);
       if(baza[pomoc].odpowiedz_uzytkownika==baza[pomoc].poprawna)
        punkty++;
       else
        numery_pytan_zlych[pomoc]=1;
        //system("cls");
    }

}
void wynik(int n, int punkty)
{
    double n1=n, punkty1=punkty;
    double wynik_w_proc;

    wynik_w_proc=(punkty1/n1)*100;
    cout<<"***********WYNIK***********"<<endl;
    cout<<"Odpowiedziales poprawnie na "<<punkty<<" odpowiedzi."<<endl;
    cout<<"Twoj wynik wynosi: "<< setprecision( 2 ) <<wynik_w_proc<<"%"<<endl;
}
void bledne_odp(int *numery_pytan_zlych,pytania *baza,int x)
{
    cout<<"*****TWOJE BLEDNE ODPOWIEDZI*****"<<endl;
    cout<<"Odpowiedzi w ktorych udzieliles zlej odpowiedzi to:"<<endl<<endl;
    for(int i=0; i<x; i++)
    {
        if(numery_pytan_zlych[i]==1)
        {
            cout<<"**"<<endl;
            cout<<baza[i].pytanie<<endl;
            cout<<"Poprawna odpowiedzial byla '"<<baza[i].poprawna<<"' ,czyli: ";
            switch(baza[i].poprawna.at(0))
            {
            case 'a':
                cout<<baza[i].odpowiedzA<<endl;
                break;
            case 'b':
                cout<<baza[i].odpowiedzB<<endl;
                break;
            case 'c':
                cout<<baza[i].odpowiedzC<<endl;
                break;
            case 'd':
                cout<<baza[i].odpowiedzD<<endl;
                break;
            }
            cout<<"Natomiast Ty wybrales odpowiedz '"<<baza[i].odpowiedz_uzytkownika<<"', czyli: ";
            switch(baza[i].odpowiedz_uzytkownika.at(0))
            {
            case 'a':
                cout<<baza[i].odpowiedzA<<endl;
                break;
            case 'b':
                cout<<baza[i].odpowiedzB<<endl;
                break;
            case 'c':
                cout<<baza[i].odpowiedzC<<endl;
                break;
            case 'd':
                cout<<baza[i].odpowiedzD<<endl;
                break;
            }
cout<<"**"<<endl<<endl;
        }
    }
}

Chciałem też dodać, że jestem początkujący i z góry przepraszam jeśli zrobiłem jakieś rażące błędy w moim kodzie.

1
komentarz 7 stycznia 2019 przez MikDal Mądrala (5,660 p.)

Używając rozwiązania @j23  bez używania tych funkcji (nie jestem super biegły w C/C++ a średnio mam teraz czas szukać jak przerobić wskaźniki na interatory). Także w taki prosty "starodawny sposób" zrobiłbym o tak:

void losuj_pytanie(int n, int wylosowanych, int *czy_wylosowane, int *numery_pytan, int x, int *TablicaNumerowZpytaniami)
{
    srand(time(0));
    for (int i = 0; i < n; i++)
    {
        numery_pytan[i] = i;
    }
    for (int i = 0; i < n; i++)
    {
        numery_pytan[rand() % n] = numery_pytan[rand() % n];
    }
}

 

1
komentarz 7 stycznia 2019 przez j23 Mędrzec (195,240 p.)

Oj, pewny jesteś pętli mieszającej?

 

Jak już kopiować std::shuffle, to tak:

for (int i = n - 1; i > 0; --i)
{
	std::swap(numery_pytan[i], numery_pytan[rand() % i]);
}

 

komentarz 7 stycznia 2019 przez MikDal Mądrala (5,660 p.)
Nie widzę jakiś  wad tego rozwiązania, masz jakiś pomysł?
1
komentarz 7 stycznia 2019 przez j23 Mędrzec (195,240 p.)
IMO wadą jest to, że nadpisujesz wartości, zamiast zamieniać je miejscami. W efekcie pewne wartości mogą zniknąć, a inne pojawić się wielokrotnie.
komentarz 7 stycznia 2019 przez MikDal Mądrala (5,660 p.)
Masz rację, nie zauważyłem tego. Zedytowałem swoją odpowiedź, aby ta wiedza trafiła również do innych. Dzięki :).

1 odpowiedź

+1 głos
odpowiedź 7 stycznia 2019 przez MikDal Mądrala (5,660 p.)
edycja 7 stycznia 2019 przez MikDal
 
Najlepsza

Program wysypuje się ponieważ algorytm losujący może wybrać pytanie o indeksie 75 do puli. Co kończy się tym, że podświetlone liniie przybierają formę baza[75[......, gdzie sama definicja zmiennej to baza[75].

for (int i = 0; i < n; i++)
    {
        pomoc = numery_pytan[i];
        cout << "***PYTANIE " << i + 1 << " na " << n << "***" << endl << endl;
        cout << baza[pomoc].pytanie << endl;
        cout << "A. " << baza[pomoc].odpowiedzA << endl;
        cout << "B. " << baza[pomoc].odpowiedzB << endl;
        cout << "C. " << baza[pomoc].odpowiedzC << endl;
        cout << "D. " << baza[pomoc].odpowiedzD << endl;
        cout << endl;
        cout << "Twoja odpowiedz to: ";
        cin >> baza[pomoc].odpowiedz_uzytkownika;
        cout << endl;
        transform(baza[pomoc].odpowiedz_uzytkownika.begin(), baza[pomoc].odpowiedz_uzytkownika.end(), baza[pomoc].odpowiedz_uzytkownika.begin(), ::tolower);
        if (baza[pomoc].odpowiedz_uzytkownika == baza[pomoc].poprawna)
            punkty++;
        else
            numery_pytan_zlych[pomoc] = 1;
        //system("cls");
    }

Używając rozwiązania @j23 (umieszczonego w komentarzu) bez używania tych funkcji iota i shuffle w taki prosty "starodawny sposób" zrobiłbym o tak:

EDYCJA: I okazuje się, że poniższy sposób nie jest do końca poprawny!

void losuj_pytanie(int n, int wylosowanych, int *czy_wylosowane, int *numery_pytan, int x, int *TablicaNumerowZpytaniami)
{
    srand(time(0));
    for (int i = 0; i < n; i++)
    {
        numery_pytan[i] = i;
    }
    for (int i = 0; i < n; i++)
    {
        numery_pytan[rand() % n] = numery_pytan[rand() % n];
    }
}

Poprawny sposób losowania pytań:

Po odpowiedzi udzielonej przez @j23 w komentarzach do pytania jestem zmuszony zedytować odpowiedź. W kodzie powyżej mogło dojść do momentu, w którym jedno pytanie pojawia się wielokrotnie. Rozwiązaniem jest zastosowanie funkcji bibliotecznej std::swap. Dzięki @j23!

for (int i = n - 1; i > 0; --i)
{
    std::swap(numery_pytan[i], numery_pytan[rand() % i]);
}

 

komentarz 7 stycznia 2019 przez kamasazi98 Początkujący (410 p.)

Dziękuje za wyjaśnienie gdzie leży problem i także @j23 za napisanie tego algorytmu,
 

for (int i = n - 1; i > 0; --i)
{
    std::swap(numery_pytan[i], numery_pytan[rand() % i]);
}

ponieważ on pomógł rozwiązać w sumie wszystko. 
Dziękuje jeszcze raz wszystkim za pomoc i przepraszam jeśli kogoś krew zalewała patrząc na mój program w przyszłości postaram się pisać przejrzyściej 

komentarz 7 stycznia 2019 przez j23 Mędrzec (195,240 p.)
W przyszłości staraj się używać funkcji/klas z biblioteki standardowej.

Podobne pytania

0 głosów
4 odpowiedzi 343 wizyt
0 głosów
0 odpowiedzi 170 wizyt
pytanie zadane 20 listopada 2019 w C i C++ przez Char Mander Nowicjusz (180 p.)
0 głosów
1 odpowiedź 978 wizyt

93,483 zapytań

142,417 odpowiedzi

322,763 komentarzy

62,895 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj

Kursy INF.02 i INF.03
...