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

std::cin - sprawdzanie co się pod nim kryje

Ostatnio zmodyfikowano 2017-04-01 12:37
Autor Wiadomość
Qabrix
Temat założony przez niniejszego użytkownika
std::cin - sprawdzanie co się pod nim kryje
» 2017-03-25 09:49:53
Witam, napisałem program, który działa bez zarzutu, jeżeli dane zostaną wpisane poprawnie. Problem zaczyna się, gdy wpisze się dane, niekoniecznie tak jak było to przewidziane w programie. Naturalnie więc zacząłem to zabezpieczać. Podczas zabezpieczania narodziły się jednak w mojej głowie trzy pytania, ale zanim je przedstawie najpierw wklejam kod:

Wyjaśnienie działania programu dla ułatwienia odczytania kodu:
Po odpaleniu programu, prosi nas on kolejno o podanie nazwy i modelu 3 samochodów. Nazwę i model podajemy wpisując je w jednym ciągu oddzielając spacjami. Po naciśnięciu pierwszej spacji program zapisuje wyraz po lewej stronie od spacji jako nazwę samochodu, a wszystko co znajdzie się po jej prawej stronie jako model, aż do czasu naciśnięcia entera. Potem program prosi o podanie nazwy i modelu kolejnego samochodu, a następnie trzeciego.

Następnie program prosi nas o podanie pojemności silnika każdego z samochodów i ich prędkość maksymalną. Na koniec program wypisuje wszystkie dane.

Jeżeli dane zostaną wprowadzone poprawnie, konsola będzie wyglądała tak:

-----------------------------------------------------------
Podaj nazwe i model samochodu nr 1: Audi Cope
Podaj nazwe i model samochodu nr 2: Fiat Chrome v2
Podaj nazwe i model samochodu nr 3: Soda Octavia
Podaj pojemnosc silnikow dla samochodu - Audi  Cope:
0.64

Podaj predkosc maksymalna dla samochodu: Audi  Cope
140

Podaj pojemnosc silnikow dla samochodu - Fiat  Chrome v2:
1.2

Podaj predkosc maksymalna dla samochodu: Fiat  Chrome v2
220

Podaj pojemnosc silnikow dla samochodu - Soda  Octavia:
3

Podaj predkosc maksymalna dla samochodu: Soda  Octavia
300

Twoje Dane:
Samochod nr 1 : Audi  Cope
Pojemnosc jego silnika: 0.64
Jego Predkosc maksymalna: 140

Samochod nr 2 : Fiat  Chrome v2
Pojemnosc jego silnika: 1.2
Jego Predkosc maksymalna: 220

Samochod nr 3 : Soda  Octavia
Pojemnosc jego silnika: 3
Jego Predkosc maksymalna: 300

------------------------------------------------------------

Kod mojego programu:


C/C++
#include <iostream>
#include <conio.h>
#include<string>
int main()
{
    using namespace std;
    int rozmiar = 50;
    char nazwa[ 6 ][ rozmiar ];
    double dane[ 3 ][ 2 ];
   
    for( int i = 0; i < 6; i++ )
    {
        if( i % 2 == 0 ) {
            cout << "Podaj nazwe i model samochodu nr " <<( i / 2 + 1 ) << ": ";
            cin >> nazwa[ i ];
        }
       
        else cin.get( nazwa[ i ], rozmiar );
       
    }
   
   
   
    for( int i = 0; i < 3; i++ )
    {
        cout << "Podaj pojemnosc silnikow dla samochodu - " << nazwa[( i * 2 ) ] << " " << nazwa[( i * 2 + 1 ) ] << ": " << endl;
       
        do
        {
            cin.clear();
            cin.sync();
            cin >> dane[ i ][ 0 ];
            if( !cin.good() )
                 cout << endl << "Podaj poprawne dane!" << endl;
           
        } while( !cin.good() );
       
        cout << endl;
       
        cout << "Podaj predkosc maksymalna dla samochodu: " << nazwa[( i * 2 ) ] << " " << nazwa[( i * 2 + 1 ) ] << endl;
       
        do
        {
            cin.clear();
            cin.sync();
            cin >> dane[ i ][ 1 ];
            if( !cin.good() )
                 cout << endl << "Podaj poprawne dane!" << endl;
           
        } while( !cin.good() );
       
        cout << endl;
    }
   
    cout << "Twoje Dane: " << endl;
   
    for( int i = 0; i < 3; i++ ) {
        cout << "Samochod nr " <<( i + 1 ) << " : " << nazwa[( i * 2 ) ] << " " << nazwa[( i * 2 + 1 ) ] << endl;
        cout << "Pojemnosc jego silnika: " << dane[ i ][ 0 ] << endl;
        cout << "Jego Predkosc maksymalna: " << dane[ i ][ 1 ] << endl;
        cout << endl;
    }
   
   
   
    getch();
    return( 0 );
}

Problemy i pytania z kodem związane:

1. Pierwszym pytaniem jest to, dlaczego przy takim zapisie jaki jest w kodzi:

C/C++
for( int i = 0; i < 6; i++ )
{
    if( i % 2 == 0 ) {
        cout << "Podaj nazwe i model samochodu nr " <<( i / 2 + 1 ) << ": ";
        cin >> nazwa[ i ];
    }
   
    else cin.get( nazwa[ i ], rozmiar );
   
}

po podaniu poprawnie nazwy i modelu samochodu, po naciśnięciu entera, program od razu poprosi nas o podanie kolejnego samochodu (i to bez czyszczenia strumienia);
a przy takim zapisie:

C/C++
for( int i = 0; i < 6; i++ )
{
    if( i % 2 == 0 )
         cout << "Podaj nazwe i model samochodu nr " <<( i / 2 + 1 ) << ": ";
   
   
    cin.clear();
    cin.sync();
    cin.get( nazwa[ i ], rozmiar );
   
}

muszę nacisnąć dwa razy enter zanim poprosi mnie o podanie kolejnego samochodu, oraz czemu ten zapis:


C/C++
for( int i = 0; i < 6; i++ )
{
    if( i % 2 == 0 )
         cout << "Podaj nazwe i model samochodu nr " <<( i / 2 + 1 ) << ": ";
   
    cin.get( nazwa[ i ], rozmiar ).get();
   
}

powoduje błąd.


2. Nadal pytanie dotyczy tego samego fragmentu kodu:

C/C++
for( int i = 0; i < 6; i++ )
{
    if( i % 2 == 0 ) {
        cout << "Podaj nazwe i model samochodu nr " <<( i / 2 + 1 ) << ": ";
        cin >> nazwa[ i ];
    }
   
    else cin.get( nazwa[ i ], rozmiar );
   
}

chciałbym go zabezpieczyć w taki sposób, że jeżeli zostanie podana tylko nazwa samochodu bez modelu, to program zwróci na to uwagę i poprosi o podanie poprawnych danych. Na razie to wygląda tak:

----------------------------------------------------------------------------------------------------------
Podaj nazwe i model samochodu nr 1: Audi
Podaj nazwe i model samochodu nr 2: Podaj nazwe i model samochodu nr 3: Podaj pojemnosc silnikow dla
 samochodu - Audi :
----------------------------------------------------------------------------------------------------------

Najlogiczniejszym rozwiązaniem wydaje mi się dodanie jakiegoś if'a, który będzie sprawdzał czy nie znalazł się w cin'ie za szybko enter, problem w tym, że nie wiem jak to sprawdzić (próbowałem czymś w tym stylu if(cin == '\n'))
Także pytanie dotyczy tego jak sprawdzić co kryje się załadowane w cin'ie. Albo jak lepiej rozwiązać ten problem (Chociaż i tak byłbym wdzięczny jeżeli znalazłaby się odpowiedź na to jak sprawdzić cina).

3.W fragmencie programu

C/C++
do
{
    cin.clear();
    cin.sync();
    cin >> dane[ i ][ 1 ];
    if( !cin.good() )
         cout << endl << "Podaj poprawne dane!" << endl;
   
} while( !cin.good() );

cout << endl;
}

Wiadomo, że jeżeli podamy 2 liczby to druga zostanie pominięta i program zadziała poprawnie, ale jednak chciałbym tego uniknąć i żeby program powiadomił nas o tym, że potrzebna mu tylko jedna liczba i ponowił prośbę. Pytanie, jak to zrobić?

Z góry dziękuję za pomoc :)




@EDIT jeszcze jedno pytanie na szybko, przy takim zapisie nie udaje mi się przekazać danych z tablicy do stringa, jak więc to zrobić?
string a = dane[ i ][ 0 ];
P-159366
j23
» 2017-03-25 11:39:42
istream::get po napotkaniu znaku końca linii nie ściąga go ze strumienia, dlatego następne wywołania zwracają puste łańcuchy znakowe.

Możesz czytać tak:
cin.get( nazwa[ i ], rozmiar ).ignore( numeric_limits < streamsize >::max(), '\n' );

choć sensowniej byłoby użyć metody getline:
cin.getline( nazwa[ i ], rozmiar );


jak więc to zrobić?
string a = dane[ i ];
P-159369
Qabrix
Temat założony przez niniejszego użytkownika
» 2017-03-25 12:03:32
Dzieki za odpowiedz j23, tyle ze nie do konca wiem czego dotyczyla. W sensie ten zapis z get jaki teraz mam dziala bez zarzutow.

A co do drugiej odpowiedzi, to czy przy takim zapisie jak podales to na pewno tak zadziala? Bo pod powiedzmy dane[0][0] bede mial zapisana pojemnosc silnika dla pierwszego samochodu,a pod dane[0][1] jego maksymalna predkosc, co jezeli bede chcial wczytac tylko np maksymalna predkosc pierwszego samochodu do stringa?
P-159372
j23
» 2017-03-25 18:08:38
Dobra, nie zauważyłem, że używasz tam operatora >>. Chociaż wiesz, jak działa get :P Odnośnie pytania drugiego: zamiast get użyj getline - ta pierwsza metoda, jak nic nie przeczyta do bufora, ustawia strumień w stan fail. Rezultat tego stanu znasz.

to czy przy takim zapisie jak podales to na pewno tak zadziala?
Jeśli dane to tablica nazw (lub innych łańcuchów znakowych), a na to wygląda, to tak. Choć nie rozumiem, dlaczego od razu nie użyjesz klasy std::string, zamiast bawić się tablicami znakowymi.

Gdyby dane była tablicą np. int[][], wtedy musiałbyś przekonwertować wartość:
string a = to_string( dane[ i ][ 0 ] );
P-159396
Qabrix
Temat założony przez niniejszego użytkownika
» 2017-03-26 21:08:54
Dobra, dzięki za odpowiedź. A co do tego czemu bawię się z tablicami zamiast stringiem, to tylko w celach edukacyjnych, żeby poćwiczyć działanie C++ w różnych przypadkach.
P-159448
Qabrix
Temat założony przez niniejszego użytkownika
» 2017-03-29 23:21:41
Nie chcę zakładać nowego tematu, ale nadal po głowie mi krąży jedno pytanie, na które nadal nie znalazłem odpowiedzi w tym poscie.

Na najprostszym przykładzie, jeżeli w konsole wpiszemy taki ciąg znaków -> "pierwszyelementtablicy drugielementtablicy", to po naciśnięciu enter, przy kodzie podanym poniżej, do tablicy zostaną wczytane dwa elementy.

Wyrażenie "pierwszyelementtablicy" do dane[0], a wyrażenie "drugielementtablicy" do dane[1].

Pytanie brzmi, jak wprowadzić w tym kodzie takie zabezpieczenie, które w przypadku wpisania np. tylko w konsoli "pierwszyelementtablicy", zapobiegnie wystąpieniu błędu w programie (ponieważ naturalnie wiemy, że drugi element nie zostanie wczytany).

Koniecznie chcę, aby dane podawać w jednym ciągu. Wiem, że jeżeli bym dodał cin.get(), lub cin.sync(); to program, by zadziałał bez błędów, ale bym musiał podawać dane po kolei.

C/C++
char dane[ 2 ][ 50 ];

for( int i = 0; i < 2; i++ )
{
    if( i % 2 == 0 ) {
       
        cout << "Podaj dwa elementy do tablicy \"dane\" w jednym ciagu znakow (spacja oddziela dwa elementy)" << endl;
        cin >> dane[ i ];
    }
   
    else cin >> dane[ i ];
   
}
P-159592
karambaHZP
» 2017-03-30 01:42:27
C/C++
std::string tab[ size ]; // constexpr int size = 2;
std::string tmp;
int i = 0;
while( std::getline( std::cin, tmp ) && !tmp.empty() && i < size ) {
    tab[ i++ ] = tmp;
}
P-159594
j23
» 2017-03-30 12:56:53
C/C++
string s;

getline( cin, s );
istringstream iss( s );
iss >> tab[ 0 ] >> tab[ 1 ];
O to chodzi?
P-159598
« 1 » 2 3
  Strona 1 z 3 Następna strona