Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++] Test z matematyki - Program nie czyta poprawnie struktury pytań z pliku binarnego

Ostatnio zmodyfikowano 2016-01-23 14:10
Autor Wiadomość
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.

C/C++
#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 /* (pes/-48));
            }   
            suma=suma%10;
            suma=10-suma;
            suma+=48;
            if (suma!=pes[10]) return 0;
        else return 1;
        }
       
        [/cpp] */
P-143835
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-c

i niby robisz to samo, ale znalazłem błąd w długości pobieranego do zapisu bufora
 bo masz

C/C++
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 ); // <--- tu długość bufora w strukturze 30, pobierasz 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 :)


P-143845
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.
P-143865
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.
C/C++
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 !
P-143880
lukaszek016
Temat założony przez niniejszego użytkownika
» 2016-01-22 21:16:08
Ok znalazłem błąd. W funkcji test linijkę

C/C++
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?
P-143901
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.
P-143908
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:

C/C++
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?
P-143914
« 1 »
  Strona 1 z 1