aus std::istream den Wert extrahieren.

BLR

Erfahrenes Mitglied
Hallo liebe Gemeinde,

Ich schreibe eine Funktion, die die Eingabe überprüfen soll.
Diese Eingabe kommt in den "cin"-Eingabestrom. Den übergebe ich über "std::istream" an meine Funktion.
Um auf bestimmte Eigenschaften zu prüfen, brauche ich den übergebenen Wert, der sich gerade im std::istream befindet.

Hier mein Code:

Aufruf:
C++:
main(int argc, char** argv){
        int zahl(0);
        cin >> zahl;
        checkInput(cin, sizeof(zahl)); //Aufruf
}
bool checkInput(std::istream& in,  int size) {
    int checkValue(0);
    char value[size];
  
    in.getline(value, size);
    stringstream ss;
    ss << value;
    ss >> checkValue;
    cout << checkValue << endl; //kommt 0 raus, obwohl ich bsp. -5 eingegeben habe.
       
    return true;
}

Wie kriege ich den tatsächlichen Inhalt aus dem std::istream :) danke für jeden tipp.
 
Hallo BLR

Zuerst zu deinem Problem:
C++:
std::cin >> zahl;

Liest die Zahl ein nachdem du die Leertaste gedrückt hast. Aber eben nur die Zahl. Im Eingabestrom bleibt weiterhin das Leerzeichen (z.B. \n oder \r\n) vorhanden. std::istream::getline liest bis zum nächsten Zeilenseparator ein, dieser ist ja aber unmittelbar am Anfang. Entsprechend ist nachher in value nichts, was du überprüfen könntest. Das ganze ist ein bekanntes Problem und Lösungen sind nicht wirklich vorhanden, viel mehr einfach Workarounds oder die Verwendung von Funktionen mit nicht-standardisierten Nebeneffekten wie fflush(stdin) oder std::istream::sync.

Bezüglich deines Codes allgemein: Warum C und C++ mischen? Deine Variante ist hochgradig unsicher, sobald eine Zahl mit mehr als 3 Stellen eingegeben wird fliegt dir das ganze um die Ohren (wenn das Leerzeichenproblem behoben wäre), da du dann über dein Array hinaus schreibst und liest.

C++:
bool checkInput(std::istream& in, int size) {
     int checkValue = 0;
     std::string value;
     if(!std::getline(in, value)) {
          return false;
     }

     std::stringstream stream;
     stream << value;
     if(!(stream >> checkValue)) {
         return false;
     }
     return true;
}

Viele Grüsse
Cromon
 
Hallo,

was du einmal von der Standardeingabe gelesen hast, kannst du nicht nochmal von dort lesen. Speichere am besten deine Eingabe in einem String und führe alle Operationen damit durch.
C++:
std::string str;
std::cin >> str;
int zahl = atoi(str.c_str());
checkInput(str);
Gruß
MCoder
 
Hi

Oder wenn man einen modernen C++-Compiler verwendet:
C++:
std::string str;
std::cin >> str;
int zahl = std::stoi(str);

Viele Grüsse
Cromon
 
Hallo BLR,

durch deinen Aufruf cin >> zahl wird der erste Wert des istream direkt zahl zugeordnet und vom Stream entfernt!
Dadurch ist er danach leer und du erhälst 0 in der Ausgabe unten.

Wenn du in dem Programm statt "-5" einmal "1 -5" eingibst, wirst du sehen, dass unten -5 herauskommt und zahl 1 enthält.

Wenn du die Zeile 3 auskommentierst, funktioniert dein Programm wie gewünscht.
Vielleicht möchtest du so etwas haben:

C++:
#include <iostream>
#include <sstream>
using namespace std;
bool checkInput(std::istream& in,  int* pOut) ;

int main(int argc, char** argv)
{
    int zahl;
    while(true)
    {
        if(checkInput(cin, &zahl))
        {
            cout << "success: " << zahl << endl;
            break;
        }
        else cout << "invalid input! enter a number\n";
    }
}
bool checkInput(std::istream& in,  int* pOut)
{
    if(!pOut) return false;
   
    string ret="";
    getline(in, ret);
   
    for(size_t i = 0; i < ret.length(); ++i)
    {
        if(!isdigit(ret[i])) return false;
    }
   
    stringstream ss;
    ss << ret;
    ss >> *pOut;
   
    //on error return false  
    return true;
}
Gib bei diesem Code mal eine Zahl und einen Buchstaben ein, dann siehst du, wie es funktioniert.


Wenn du das für sämtliche nummerische Datentypen machen möchtest, kannst du eine Template Funktion verwenden:

C++:
#include <iostream>
#include <sstream>
using namespace std;


template<typename T>
bool checkInput(std::istream& in, T* pOut)
{
   if(!pOut) return false;
   
   string ret="";
   getline(in, ret);
   
   for(size_t i = 0; i < ret.length(); ++i) //hier könnte man noch generische Switches einbauen, sofern nicht nur nummerische Datentypen T von Interesse sind..
   {
     if(!isdigit(ret[i])) return false;
   }
   
   stringstream ss;
   ss << ret;
   ss >> *pOut;
   
  //on error return false   
  return true;
}

int main(int argc, char** argv)
{
   int zahl; //oder long zahl oder ...
   while(true)
   {
     if(checkInput(cin, &zahl))
     {
       cout << "success: " << zahl << endl;
       break;
     }
     else cout << "invalid input! enter a number\n";
   }
}


Bei Fragen gerne melden
vg
kickerxy
 
Vielen vielen Dank für eure zahlreichen Antworten.
@Cromon
In welcher Zeile habe ich C und C++ gemischt?
Ich dachte, wenn ich atoi von C verwende um die Eingabe ins Int umzuwandelnt, würde ich C und C++ mischen :)

@kickerxy123
Diese Vorgehensweise habe ich ebenfalls ausprobiert (oder so ähnlich^^)
Jedenfalls hatte ich nach std::getline nichts in meinem String stehen, aber das wundert mich jetzt auch nicht, wenn du sagst, dass der Input aus dem Stream verschwindet, sobald man eingelsen hat.
Zu deiner ersten Funktion:
Ich komme zu dem Schluss, dass wenn man doch den original-Wert in der Funktion verarbeiten will, muss man die Eingabe direkt in der Funktion tätigen.
Die Frage, die dabei entsteht ist, wozu braucht man dann den ersten istream-Argument?
Ich habe auch geschrieben: getline(cin, zahl), und es genauso funktioniert.

Danke jedenfalls für die Auflärung vom istream-verhalten :)
 
Gern geschehen,
du hast natürlich recht, den Parameter istream braucht man überhaupt nicht. Da habe ich nicht weiter drüber nachgedacht ;) du kannst problemlos cin als 1. Parameter bei getline nehmen
 

Neue Beiträge

Zurück