lukaszek016 Temat założony przez niniejszego użytkownika |
[C++] Test z matematyki - Program nie czyta poprawnie struktury pytań z pliku binarnego » 2016-01-20 21:09:42 Witam. Mam problem z projektem na zajęcia z programowania. Mam do zrobienia test z matematyki. Nie ma program jeszcze wszystkich funkcji, które zamierzam zrobić, póki co zrobiłem dodawanie użytkownika, po tym jak program nie znajdzie w bazie po peselu, dodawanie pytań oraz rozwiązywanie testu przy czym w rozwiązywaniu problem pojawił się z wyświetlaniem pytań, gdyż nie wyświetla w ogóle. I po podaniu peselu i uruchomieniu funkcji test jest piknięcie w głośnikach i dziwne znaczki zamiast odpowiedzi. Hasło do administrowania to matematyka . Na początek dodajcie sobie jakieś pytanie i stwórzcie testowanego. Program nie zlicza jeszcze punktów, bo myślę na razie jak zrobić sprawdzanie odpowiedzi i dopasowanie ich do liter A B C D. Proszę o pomoc. Prawdopodobnie zrobiłem gdzieś błąd w czytaniu z pliku. Wklejam kod. Z góry dziękuję za pomoc. #include<iostream> #include<cmath> #include<conio.h> #include<cstdlib> #include<string> #include<fstream> #include<cstring> #include<ctime>
using namespace std;
string PL( const char * text ) { std::string result; for(; * text; text++ ) switch( * text ) { case 'ą': result += static_cast < char >( 0xa5 ); break; case 'ć': result += static_cast < char >( 0x86 ); break; case 'ę': result += static_cast < char >( 0xa9 ); break; case 'ł': result += static_cast < char >( 0x88 ); break; case 'ń': result += static_cast < char >( 0xe4 ); break; case 'ó': result += static_cast < char >( 0xa2 ); break; case 'ś': result += static_cast < char >( 0x98 ); break; case 'ż': result += static_cast < char >( 0xbe ); break; case 'ź': result += static_cast < char >( 0xab ); break; case 'Ą': result += static_cast < char >( 0xa4 ); break; case 'Ć': result += static_cast < char >( 0x8f ); break; case 'Ę': result += static_cast < char >( 0xa8 ); break; case 'Ł': result += static_cast < char >( 0x9d ); break; case 'Ń': result += static_cast < char >( 0xe3 ); break; case 'Ó': result += static_cast < char >( 0xe0 ); break; case 'Ś': result += static_cast < char >( 0x97 ); break; case 'Ż': result += static_cast < char >( 0xbd ); break; case 'Ź': result += static_cast < char >( 0x8d ); break; default: result += * text; break; } return result; }
struct odpowiedz { char tresc[ 30 ]; bool prawda; };
struct pytania { int id_pytania; char tresc_pytania[ 150 ]; odpowiedz odpowiedz1; odpowiedz odpowiedz2; odpowiedz odpowiedz3; odpowiedz odpowiedz4; };
struct testowani { int id_testowanego; char imie[ 20 ]; char nazwisko[ 20 ]; char pesel[ 11 ]; int wynik; };
void wyniki(); void wybor_testowanego(); void dodawanie_pytania(); void administrowanie(); void dodawanie_testowanego(); int menuGlowne(); int test( char * ); void wpisywanieHasla(); char czyPoprawny( char pes[] );
int main()
{ cout << PL( "Witaj w teście z matematyki" ) << endl; menuGlowne(); return 0; }
void wyniki() { cout << "Wyniki" << endl; } void wybor_testowanego() { testowani testowany; char s_pesel[ 11 ]; cout << "Wybor testowanego" << endl; cout << PL( "Podaj swój PESEL: " ); cin >> s_pesel; fstream plik( "students.dat", ios::binary | ios::in | ios::out ); for( int i = 1;; i++ ) { plik.read( reinterpret_cast < char *>( & testowany ), sizeof( testowany ) ); if( strcmp( s_pesel, testowany.pesel ) == 0 ) test( s_pesel ); return; if( plik.eof() ) break; } cout << testowany.pesel << endl; plik.close(); cout << "Twojego peselu nie ma w bazie. Dodaj swoje dane do bazy." << endl; dodawanie_testowanego(); } void dodawanie_pytania() { pytania pytanie; int dlugoscPliku; ifstream fs; fs.open( "qs.dat", ios::binary | ios::in ); if( fs ) { fs.seekg( 0, ios::end ); dlugoscPliku = fs.tellg(); fs.seekg( 0, ios::beg ); } fs.close(); int iloscRekordow; fstream plik( "qs.dat", ios::binary | ios::out | ios::app | ios::in ); iloscRekordow = dlugoscPliku / sizeof( pytanie ); cout << "Dodawanie pytania" << endl; pytanie.id_pytania == iloscRekordow + 1; cout << PL( "Podaj treść pytania" ) << endl; cin.sync(); cin.get( pytanie.tresc_pytania, 150 ); cout << PL( "Podaj pierwszą odpowiedź" ) << endl; cin.sync(); cin.get( pytanie.odpowiedz1.tresc, 150 ); cout << "Czy ta odpowiedz jest poprawna? 1 -TAK / 0 - NIE" << endl; cin >> pytanie.odpowiedz1.prawda; cout << PL( "Podaj drugą odpowiedź" ) << endl; cin.sync(); cin.get( pytanie.odpowiedz2.tresc, 150 ); cout << "Czy ta odpowiedz jest poprawna? 1 -TAK / 0 - NIE" << endl; cin >> pytanie.odpowiedz2.prawda; cout << PL( "Podaj trzecią odpowiedź" ) << endl; cin.sync(); cin.get( pytanie.odpowiedz3.tresc, 150 ); cout << "Czy ta odpowiedz jest poprawna? 1 -TAK / 0 - NIE" << endl; cin >> pytanie.odpowiedz3.prawda; cout << PL( "Podaj czwartą odpowiedź" ) << endl; cin.sync(); cin.get( pytanie.odpowiedz4.tresc, 150 ); cout << "Czy ta odpowiedz jest poprawna? 1 -TAK / 0 - NIE" << endl; cin >> pytanie.odpowiedz4.prawda; plik.write( reinterpret_cast < char *>( & pytanie ), sizeof( pytanie ) ); plik.close(); administrowanie(); }
void wpisywanieHasla() { string haslo; string wpisane; haslo = "matematyka"; cout << PL( "Podaj hasło dostępu... " ); do { cin >> wpisane; cout << "\n"; if( wpisane != haslo ) cout << PL( "Nieprawidłowe hasło, podaj ponownie" ) << endl; } while( wpisane != haslo ); administrowanie(); } void administrowanie() { system( "cls" ); cout << "MENU ADMINISTRATORA" << endl; cout << PL( "Wybierz, co chcesz zrobić" ) << endl; cout << PL( "1. Dodaj pytanie \n2. Przeglądaj wyniki \n3. Powrót do menu głównego \nInny klawisz -> Zakończ" ) << endl; char wybor; wybor = getch(); if( wybor == '1' ) dodawanie_pytania(); else if( wybor == '2' ) wyniki(); else if( wybor == '3' ) menuGlowne(); else exit( 0 ); } void dodawanie_testowanego() { int dlugoscPliku; fstream fs; fs.open( "students.dat", ios::binary | ios::in ); if( fs ) { fs.seekg( 0, ios::end ); dlugoscPliku = fs.tellg(); fs.seekg( 0, ios::beg ); } fs.close(); char poprawnoscPeselu; testowani testowany; float iloscRekordow; fstream plik( "students.dat", ios::binary | ios::out | ios::app | ios::in ); iloscRekordow = dlugoscPliku / sizeof( testowany ); cout << "Dodawanie testowanego" << endl; testowany.id_testowanego = iloscRekordow + 1; cout << PL( "Podaj imię: " ); cin >> testowany.imie; cout << PL( "Podaj nazwisko: " ); cin >> testowany.nazwisko; cout << PL( "Podaj PESEL: " ); do { cin >> testowany.pesel; poprawnoscPeselu = czyPoprawny( testowany.pesel ); cout << "\n"; if( poprawnoscPeselu == 0 ) cout << PL( "Podaj poprawny 11-cyfrowy PESEL!" ) << endl; } while( poprawnoscPeselu == 0 ); plik.write( reinterpret_cast < char *>( & testowany ), sizeof( testowany ) ); plik.close(); cout << "\nNowy testowany dodany poprawnie!\n" << endl; } int menuGlowne() { system( "cls" ); cout << PL( "MENU GŁÓWNE" ) << endl; cout << PL( "1. Rozwiąż test" ) << endl << PL( "2. Administruj danymi" ) << endl << PL( "Inny klawisz -> Wyjdź z programu" ) << endl; char decyzja; decyzja = getch(); if( decyzja == '1' ) wybor_testowanego(); else if( decyzja == '2' ) wpisywanieHasla(); else return 0; } int test( char * pesel ) { int wynik_testu = 0; pytania pytanie; int dlugoscPliku; fstream plik( "qs.dat", ios::binary | ios::out | ios::app | ios::in ); if( plik ) { plik.seekg( 0, ios::end ); dlugoscPliku = plik.tellg(); plik.seekg( 0, ios::beg ); } int iloscRekordow; plik.close(); iloscRekordow = dlugoscPliku / sizeof( pytanie ); cout << PL( "Ilość pytań " ) << iloscRekordow << endl; int los = 2; los = rand() %( iloscRekordow + 1 ); system( "cls" ); cout << PL( "Twój PESEL to " ) << pesel << endl; cout << PL( "Za chwilę zostanie wyświetlone 10 pytań.\nNa każde z nich odpowiedz wciskając odpowiadającą \nodpowiedzi literę na klawiaturze.\n" ) << endl; cout << PL( "Aby rozpocząć test, naciśnij Enter..." ) << endl; fstream plik2( "qs.dat", ios::binary ); plik2.seekp( sizeof( struct pytania ) *( los - 1 ) ); plik2.read( reinterpret_cast < char *>( & pytanie ), sizeof( pytanie ) ); cout << pytanie.tresc_pytania << endl; cout << "A. " << pytanie.odpowiedz1.tresc << endl; cout << "B. " << pytanie.odpowiedz2.tresc << endl; cout << "C. " << pytanie.odpowiedz3.tresc << endl; cout << "D. " << pytanie.odpowiedz4.tresc << endl; plik2.close(); cout << "Koniec testu" << endl; getch(); }
char czyPoprawny( char pes[ 11 ] ) { int tab[ 11 ] = { 1, 3, 7, 9, 1, 3, 7, 9, 1, 3 }; int a, suma = 0; for( a = 0; a < 10; a++ ) { suma = suma +( tab |
|
darko202 |
» 2016-01-21 08:23:56 z opisu który przedstawiłeś wynika, że problemem jest interpretacja zapisywanych, a potem czytanych danych. 1. popatrzyłem na http://codereview.stackexchange.com/questions/26344/writing-reading-data-structure-to-a-file-using-ci niby robisz to samo, ale znalazłem błąd w długości pobieranego do zapisu bufora bo masz struct odpowiedz { char tresc[ 30 ]; bool prawda; };
struct pytania { int id_pytania; char tresc_pytania[ 150 ]; odpowiedz odpowiedz1; ... };
....
void dodawanie_pytania() {... cout << "Dodawanie pytania" << endl; pytanie.id_pytania == iloscRekordow + 1; cout << PL( "Podaj treść pytania" ) << endl; cin.sync(); cin.get( pytanie.tresc_pytania, 150 ); cout << PL( "Podaj pierwszą odpowiedź" ) << endl; cin.sync(); cin.get( pytanie.odpowiedz1.tresc, 150 );
2. nie wiem, czy to wszystko, ale zacznij od tego, aby doprowadzić do zapisu i odczytu prostej struktury. np. sprawdzenie przykładu z ww. strony a potem zwiększaj złożoność struktury 3. jeśli nie znasz to koniecznie zapoznaj się z techniką debagowania programu Powodzenia :) |
|
lukaszek016 Temat założony przez niniejszego użytkownika |
» 2016-01-21 20:07:32 Zmieniłem długość bufora i dalej nie działa. Jednak gdyby to było przyczyną to funkcja test wyświetliłaby chociaż treść pytania, a ona nic nie wyświetla tylko dziwne znaki w dwóch pierwszych odpowiedziach. Możliwe, że błąd jest w zapisie struktury, albo po prostu zmienne o typie strukturalnym zapisuje się inaczej. |
|
darko202 |
» 2016-01-22 11:58:28 4. z treści odpowiedzi wnoszę, że nie przemyślałeś p3. debugowanie własnego programu rozwiązuje wiele dziwnych problemów zastanów się i wykorzystaj "możliwość zatrzymania w dowolnym momencie" obejrzyj stan zmiennych. np. w kolejnych krokach poniższych (p5) operacji. 5. fstream plik2( "qs.dat", ios::binary ); plik2.seekp( sizeof( struct pytania ) *( los - 1 ) ); plik2.read( reinterpret_cast < char *>( & pytanie ), sizeof( pytanie ) ); cout << pytanie.tresc_pytania << endl; cout << "A. " << pytanie.odpowiedz1.tresc << endl;
6. co robi linia ? fstream plik2( "qs.dat", ios::binary ); czy na pewno działa bez flag ? http://www.cplusplus.com/doc/tutorial/files/ np. ios::in Open for input operations. czy nie brakuje sprawdzenia ? if (myfile.is_open()) p7. powtórzenie p2 Powodzenia ! |
|
lukaszek016 Temat założony przez niniejszego użytkownika |
» 2016-01-22 21:16:08 Ok znalazłem błąd. W funkcji test linijkę plik2.seekp( sizeof( struct pytania ) *( los - 1 ) );
dałem w komentarz i wyświetliło pytanie. Jednak teraz wyświetli prawdopodobnie tylko pierwsze pytanie w pliku. A mi chodzi o to, żeby wylosowało pytanie do wyświetlenia. Chciałem to rozwiązać tak, że losuję liczbę od 1 do ilości pytań i ustawiam wskaźnik czytania przed wylosowanym rekordem. Jednak widzę, że to nie działa lub coś namieszałem w losowaniu lub w tej linijce. Jakieś pomysły? |
|
Monika90 |
» 2016-01-23 11:14:48 seekp ustawia wskaźnik zapisu, a nie odczytu. Gdybyś do odczytu używał ifstream, zamiast fstream, to kompilator by wyłapał taki błąd. |
|
lukaszek016 Temat założony przez niniejszego użytkownika |
» 2016-01-23 14:10:06 Tak, to też zauważyłem, wkleiłem tu jeszcze przed zmianą. Jednak na seekg jest identyczna sytuacja. Edit: Uruchomiłem ten program na laptopie i również z tą linijką działa. Zamiast los-1 dałem 0 i pokazuje pierwsze pytanie, a jak wpiszę 1 to drugie. Jakoś rozwiąże to losowanie. Pytanie mam jeszcze co do wyboru użytkownika. W kodzie: ifstream plik( "students.dat", ios::binary | ios::in ); for( int i = 1;; i++ ) { plik.read( reinterpret_cast < char *>( & testowany ), sizeof( testowani ) ); if( strcmp( s_pesel, testowany.pesel ) == 0 ) test( s_pesel ); if( plik.eof() ) break; }
plik.close();
Szuka w pliku wpisanego pesela. I sprawdza znajduje się taki w pliku. Jeśli tak to wykonuje funkcję test, jeśli nie to opuszcza pętlę. Jednak funkcja est wykonuje się tylko wtedy, gdy podam pesel, który jest jako pierwszy w pliku. Przy innych nie działa i przechodzi do następnego kroku w funkcji wybor_testowanego czy wypisuje, że peselu nie ma w bazie i wykonuje funkcję dodawanie_testowanego. Co jest nie tak? Może dodać umieszczanie znacznika odczytu, a pozycję brać ze zmiennej i deklarowanej w pętli for? |
|
« 1 » |