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

[C++] Zgadywanie wylosowanej liczby - jak ignorować podawanie liter?

Ostatnio zmodyfikowano 2013-05-21 00:23
Autor Wiadomość
jaro98
Temat założony przez niniejszego użytkownika
[C++] Zgadywanie wylosowanej liczby - jak ignorować podawanie liter?
» 2013-05-19 21:06:40
1. Dlaczego poniższy program (pierwszy) wypisuje "nie podales liczby z zadanego przedzialu, sprobuj jeszcze raz" (ostatnie "if") w momencie, gdy wpisze się jakiś znak? Czy to wynika z tego, że znak zostaje uznany za liczbę przez funkcję if?
2. Jeśli odpowiedź na powyższe pytanie jest twierdząca, to znaczy, że gdyby przedział był większy (niż (1,1000)) to jakiś znak mógłby zakłócić działanie programu, jeśli odpowiadająca mu liczba znajdowałaby się w przedziale?
3. Jak powinienem domyślnie rozwiązać problem wprowadzania znaków i liczb wymiernych niecałkowitych? Czy może być tak, jak podałem w drugim przykładzie (tutaj z kolei dlaczego cin.good()=1, gdy wpiszemy liczbę niecałkowitą, jeśli a to typ int - chodzi o to, że ze strumienia został wczytany tylko całkowity początek, do kropki?)?
Proszę wybaczyć, jeśli czegoś nie doczytałem.

C/C++
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
    srand( time( NULL ) );
    int liczba;
    int a;
    liczba =(( rand() % 1000 ) + 1 );
    cout << "Program wylosowal liczbe naturalna, ktora znajduje sie w przedziale od 1 do 1000. Zgadnij jaka to liczba." << endl;
    do
    {
        cin.clear();
        cin.sync();
        cin >> a;
        if( a == liczba )
             cout << "brawo, ta liczba to " << a;
       
        if( a > liczba && a <= 1000 )
             cout << "liczba jest mniejsza, sprobuj jeszcze raz" << endl;
       
        if( a < liczba && a >= 1 )
             cout << "liczba jest wieksza, sprobuj jeszcze raz" << endl;
       
        if( a > 1000 || a < 1 )
             cout << "nie podales liczby z zadanego przedzialu, sprobuj jeszcze raz" << endl;
       
    } while( a != liczba );
   
    return 0;
}
C/C++
#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
    srand( time( NULL ) );
    int liczba;
    int a;
    liczba =(( rand() % 1000 ) + 1 );
    cout << "Program wylosowal liczbe naturalna, ktora znajduje sie w przedziale od 1 do 1000. Zgadnij jaka to liczba." << endl;
    do
    {
        cin.clear();
        cin.sync();
        cin >> a;
        if( cin.good() )
        {
            if( a == liczba )
                 cout << "brawo, ta liczba to " << a;
           
            if( a > liczba && a <= 1000 )
                 cout << "liczba jest mniejsza, sprobuj jeszcze raz" << endl;
           
            if( a < liczba && a >= 1 )
                 cout << "liczba jest wieksza, sprobuj jeszcze raz" << endl;
           
            if( a > 1000 || a < 1 )
                 cout << "nie podales liczby z zadanego przedzialu, sprobuj jeszcze raz" << endl;
           
        }
        else
             cout << "nie podales liczby z zadanego przedzialu, sprobuj jeszcze raz" << endl;
       
    } while( a != liczba );
   
    return 0;
}
P-83345
pekfos
» 2013-05-19 21:30:32
1. Wczytujesz int, więc gdy podasz znak, zostanie ustawiona flaga błędu, a do zmiennej trafia 0 (to co zostało wczytane do napotkania błędnego znaku). Ostatni warunek jest spełniony dla a=0.
P-83354
Monika90
» 2013-05-19 21:36:49
Jeżeli miało być wczytane int, a na wejściu był znak który nie był cyfrą, to operator >> nie zmieni zawartości zmiennej
a
, a ponieważ ta zmienna nie była zainicjalizowana, to będzie zawierała jakieś śmieci (w C++11 jest chyba inaczej). Sprawdzanie wartość tej zmiennej za pomocą
if
 może zrobić rzecz dowolną.

Zawsze po próbie wczytania sprawdzaj stan strumienia, i to nie za pomocą good(), ale za pomocą fail(), albo za pomocą konwersji strumienia na bool. Np.
C/C++
int a;
cin >> a;
if( !cin.fail() )
{
    //OK, uzywaj a
}
else
{
    //blad
}
Albo prościej:
C/C++
int a;
if( cin >> a )
{
    //OK, uywaj a
}
else
{
    //blad
}

Jeżeli chciales wczytac int, a na wejsciu było "123.456", to zostanie wczytane "123", a w strumienu zostanie ".456". Wczytywanie zatrzymuje się na pierwszym znaku, który nie pasuje do formatu int, i znak ten zostaje w stumieniu. Tak że następna operacja wejściowa natrafi na ten właśnie znak.
P-83356
pekfos
» 2013-05-19 21:47:17
to operator >> nie zmieni zawartości zmiennej
Standard to określa, czy implementacja?

Sprawdzanie wartość tej zmiennej za pomocą
if
 może zrobić rzecz dowolną.
Dlaczego? Śmieci to takie same zera i jedynki jak w normalnych wartościach. Nie sądzę, by było tam coś nadprzyrodzonego..
P-83359
Monika90
» 2013-05-19 22:03:14
Standard to określa, czy implementacja?
Tak, to określa standard. W C++98, jeżeli nie udało się nic wczytać, to zmienna jest pozostawiana bez zmian. W C++11 do zmiennej będzie zapisane zero. To poważna zmiana.

Dlaczego? Śmieci to takie same zera i jedynki jak w normalnych wartościach. Nie sądzę, by było tam coś nadprzyrodzonego..
Zjawiska nadprzyrodzone nie istnieją, ale istnieje UB. Odczyt niezainicjalizowanej zmiennej to niezdefiniowane zachowanie. To nie znaczy, że wartość zmiennej może być dowolna, to znaczy, że w ogóle nie wiadomo co się stanie.
P-83363
jaro98
Temat założony przez niniejszego użytkownika
» 2013-05-19 22:35:53
Ok, dzięki. Jeszcze to przeanalizuję.
P-83369
Elaine
» 2013-05-20 14:26:47
Dlaczego? Śmieci to takie same zera i jedynki jak w normalnych wartościach.
LLVM uważa inaczej.

Dla funkcji:
C/C++
int foo( int x )
{
    int y;
    const int c = y ^ x;
    return c == c;
}
Clang generuje następujący IR:
define i32 @_Z3fooi(i32 %x) nounwind uwtable readnone {
  ret i32 0
}
To nie byłoby możliwe, gdyby "śmieci" były "takimi samymi zerami i jedynkami", jak w "normalnych wartościach".

Swoją drogą, ten przykład jest śmieszny, bo Clang wcześniej ostrzega:
<stdin>:1:55: warning: self-comparison always evaluates to true [-Wtautological-compare]
int foo(int x) { int y; const int c = y ^ x; return c == c; }
                                                      ^
P-83412
jaro98
Temat założony przez niniejszego użytkownika
» 2013-05-20 16:37:55
Właściwie, to nie wiem dlaczego mam sprawdzać stan strumienia za pomocą fail() a nie używać good(). One nie działają symetrycznie, w sensie, że jeśli fail()=1, to good()=0 i na odwrót?
P-83430
« 1 » 2
  Strona 1 z 2 Następna strona