Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » Anfängerfrage cin

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: > 1 <
000
20.07.2011, 15:25 Uhr
Markus_pp



Hallo zusammen.

Ich habe eine ganz einfach Methode, die eine Zahl aus der Konsole auslesen soll. Ist die Eingabe keine Zahl, soll eine Meldung ausgegeben werden, ansonsten wird die Zahl zurückgeliefert.
Gebe ich eine Zahl ein ist alles ok, nur bei einem String macht das ganze Probleme.
Bei einem String wird das ok Flag richtigerweise nicht auf true gesetzt und die Schleife sollte nochmals durchlaufen werden. Doch: Beim zweiten cin blockiert der Stream nicht mehr (der User kann keine Eingabe mehr machen) sondern die Schleife wird gleich wieder durchlaufen. Wieso? Ich dachte ich könne das Fehlerbit mit cin.clear wieder zurücksetzen, jedoch ist dem leider nicht der Fall.
Nebenbei: Es ist mir schon bewusst, dass das Programm auch einfacher zu machen wäre, jedoch bin ich eben beim C++ "spielen" auf dieses Problem gestoßen und würde gerne wissen, wieso dem so ist.



Code:
int getNumberFromConsole()
{
    int zahl = 0;
    bool ok = false;

    do
    {
        try
        {
            
            std::cout << "Bitte geben sie eine Zahl ein: ";
            std::cin >> zahl;
            
            if (std::cin.good() == true) ok = true;

            std::cin.clear();
        }
        catch (std::exception& e)
        {
            std::cout << "Ihre Eingabe war ungültig!"; // << e;
            ok = false;
        }
    } while (ok == false);

    return zahl;
}
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
001
20.07.2011, 16:24 Uhr
Tommix



Hallo,
clear löscht nur das Failflag, die ungütilgen Zeichen stehen dann aber immer noch im Puffer.
Das ist das Beispiel zu cin im MSDN:

C++:
// iostream_cin.cpp
// compile with: /EHsc
#include <iostream>
using namespace std;

int main()
{
   int x;
   cout << "enter choice:";
   cin >> x;
   while (x < 1 || x > 4)
   {
      cout << "Invalid choice, try again:";
      cin >> x;
      // not a numeric character, probably
      // clear the failure and pull off the non-numeric character
      if (cin.fail())
      {
         cin.clear();
         char c;
         cin >> c;
      }
   }
}



Es ist übrigens überflüssig, boolsche Variablen per == true und == false zu prüfen. Du schreibst doch auch nicht

C++:
if ((a == b) == true)


Besser

C++:
ok = std::cin.good();
// ...
while (!ok)



Gruß, Tommix
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
002
21.07.2011, 02:12 Uhr
0xdeadbeef
Gott
(Operator)


Ich hab dafür vor langer Zeit mal eine Funktionstemplate zusammengeschustert, die das mit stringstream erledigt:

C++:
#include <iostream>
#include <sstream>
#include <string>

template<typename result_t>
result_t read_type_ref(result_t &dest,
                       std::string const &prompt,
                       std::istream &in  = std::cin,
                       std::ostream &out = std::cout) {
  std::istringstream parser;
  std::string line;

  do {
    // Vorsicht, Porzellankiste und so.
    if(!in ) throw std::runtime_error("Eingabefehler");
    if(!out) throw std::runtime_error("Ausgabefehler");

    parser.clear();

    out << prompt << std::flush;

    std::getline(in, line);

    parser.str(line);
    parser >> dest;
  } while(!parser);

  return dest;
}

template<typename result_t>
result_t read_type(std::string const &prompt,
                   std::istream &in  = std::cin,
                   std::ostream &out = std::cout) {
  result_t result;
  return read_type_ref(result, prompt, in, out);
}


Zu benutzen beispielsweise als

C++:
int    x = read_type<int   >("Bitte geben Sie eine Ganzzahl ein: ");
double d = read_type<double>("Jetzt bitte eine Fließkommazahl: ");


...wobei der Prompt solange wiederholt wird, bis eine Zahl eingegeben wurde.

Dabei verhält std::istringstream sich genau wie andere Eingabeströme (std::cin ist ein solcher, und wenn du schon mit Dateien gearbeitet hast, std::ifstream auch), nur dass er seine Daten aus einem String bezieht.

Der Ansatz ist dann denkbar simpel: Ich hole erst eine ganze Zeile aus std::cin, stopfe die in den Stringstream und parse daraus. Das ganze wird so lange wiederholt, bis es hinhaut. Die zu erwartenden Fehler (d.h. falsche Eingaben) betreffen dann den Stringstream, und es bleiben auch keine Rückstände in std::cin, die einen später überraschen (beliebte Anfängerverwunderung ist etwa, dass std::cin.get() nicht anhält, wenn nach std::cin >> foo noch ein Zeilenumbruch in std::cin steckt). Unerwartete Fehler (dass der Programmierer einem Streams in die Hand drückt, die schon einen Fehlerstatus haben, dass an anderer Stelle der Strom geschlossen wird und andere Dinge, von denen man nicht erwartet, dass sie tatsächlich passieren) verursachen eine Exception; dafür sind die Dinger ja da.

Ich halte das in diesem Zusammenhang für eine sinnvolle Vorgehensweise, weil der Benutzer bei CLIs in der Regel erwartet, dass seine Eingabe zeilenweise verarbeitet wird und Performance hier keine Rolle spielt (Flaschenhals ist die Reaktionszeit des Anwenders).
--
Einfachheit ist Voraussetzung für Zuverlässigkeit.
-- Edsger Wybe Dijkstra

Dieser Post wurde am 21.07.2011 um 02:25 Uhr von 0xdeadbeef editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: > 1 <     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: