[Anfänger] Funktion schreiben für Falscheingaben
-
@drgreenthumb sagte in [Anfänger] Funktion schreiben für Falscheingaben:
Du solltest einen String einlesen und dann daraus eine Zahl machen
Was spricht für soetwas?
@drgreenthumb sagte in [Anfänger] Funktion schreiben für Falscheingaben:
z.B. mit atoi()
Sollte man nicht.
std::atoi()
hat undefined behaviour wenn die Zeichenkette nicht umgewandelt werden kann.@drgreenthumb sagte in [Anfänger] Funktion schreiben für Falscheingaben:
oder strtod()
Es geht um natürliche Zahlen.
-
@swordfish sagte in [Anfänger] Funktion schreiben für Falscheingaben:
Was spricht für soetwas?
Worauf willst du hinaus?
Sollte man nicht. std::atoi() hat undefined behaviour wenn die Zeichenkette nicht umgewandelt werden kann.
Du meinst also man sollte std::atoi() generell nicht verwenden oder was?
Mach den String halt max. 9. Zeichen lang, wenn du Angst hast, das Ergebnis könnte den int sprengen.Es geht um natürliche Zahlen.
ja und? Du kannst doch aus dem float ein int machen? Ggf. auch eine Fehlermeldung anzeigen, wenn eine Kommazahl eingegeben wurde.
-
@drgreenthumb sagte in [Anfänger] Funktion schreiben für Falscheingaben:
@swordfish sagte in [Anfänger] Funktion schreiben für Falscheingaben:
Was spricht für soetwas?
Worauf willst du hinaus?
Warum dieser Umweg? Warum nicht gleich lesen, was man haben will?
@drgreenthumb sagte in [Anfänger] Funktion schreiben für Falscheingaben:
Sollte man nicht. std::atoi() hat undefined behaviour wenn die Zeichenkette nicht umgewandelt werden kann.
Du meinst also man sollte std::atoi() generell nicht verwenden oder was?
Nicht, wenn nicht vorher sichergestellt ist, daß die Zeichenkette mit einem Vorzeichen und einer Ziffer oder mit einer Ziffer beginnt und die enthaltene Zahl in einen
int
passt.@drgreenthumb sagte in [Anfänger] Funktion schreiben für Falscheingaben:
Mach den String halt max. 9. Zeichen lang, wenn du Angst hast, das Ergebnis könnte den int sprengen.
Bei sonstigen fehlerhaften Eingaben bleibt trotzdem undefined behaviour.
@drgreenthumb sagte in [Anfänger] Funktion schreiben für Falscheingaben:
Es geht um natürliche Zahlen.
ja und? Du kannst doch aus dem float ein int machen? Ggf. auch eine Fehlermeldung anzeigen, wenn eine Kommazahl eingegeben wurde.
Also nochmal umständlicher. Fehlerhafte Eingaben lassen sich bei
strtod()
nicht von der Eingabe von0
unterscheiden.
-
@swordfish sagte in [Anfänger] Funktion schreiben für Falscheingaben:
Warum dieser Umweg? Warum nicht gleich lesen, was man haben will?
Tja, das ist wohl Geschmackssache und es gab ja keine Rahmenbedingungen.
Ich könnte jetzt nicht aus dem Kopf sagen, wie man das mit cin oder scanf macht.
(du scheinbar auch nicht, sonst hättest du dass ja längst?).Mein Weg funktioniert auch, wenn die Eingabe nicht aus einem Stream kommt.
[atoi] Nicht, wenn nicht vorher sichergestellt ist, daß die Zeichenkette mit einem Vorzeichen und einer Ziffer oder mit einer Ziffer beginnt und die enthaltene Zahl in einen int passt.
Bei sonstigen fehlerhaften Eingaben bleibt trotzdem undefined behaviour.Wie kommst du denn darauf?
Laut cppreference.com:
If the converted value falls out of range of corresponding return type, the return value is undefined. If no conversion can be performed, 0 is returned.
@swordfish sagte in [Anfänger] Funktion schreiben für Falscheingaben:
[strtod] Also nochmal umständlicher. Fehlerhafte Eingaben lassen sich bei strtod() nicht von der Eingabe von 0 unterscheiden.
Doch, über den endptr:
If no conversion can be performed, 0 is returned and *str_end is set to str
-
@drgreenthumb sagte in [Anfänger] Funktion schreiben für Falscheingaben:
@swordfish sagte in [Anfänger] Funktion schreiben für Falscheingaben:
Warum dieser Umweg? Warum nicht gleich lesen, was man haben will?
Tja, das ist wohl Geschmackssache und es gab ja keine Rahmenbedingungen.
Ich könnte jetzt nicht aus dem Kopf sagen, wie man das mit cin oder scanf macht.
(du scheinbar auch nicht, sonst hättest du dass ja längst?).int value; if( !( std::cin >> value ) ) std::cerr << "Error!\n"; if( std::scanf( "%d", &value ) != 1 ) std::cerr << "Error!\n";
?
@drgreenthumb sagte in [Anfänger] Funktion schreiben für Falscheingaben:
@swordfish sagte in [Anfänger] Funktion schreiben für Falscheingaben:
[atoi] Nicht, wenn nicht vorher sichergestellt ist, daß die Zeichenkette mit einem Vorzeichen und einer Ziffer oder mit einer Ziffer beginnt und die enthaltene Zahl in einen int passt.
Bei sonstigen fehlerhaften Eingaben bleibt trotzdem undefined behaviour.Wie kommst du denn darauf?
Laut cppreference.com:
If the converted value falls out of range of corresponding return type, the return value is undefined. If no conversion can be performed, 0 is returned.
http://www.cplusplus.com/reference/cstdlib/atoi/ und der Standard sagt nichts über das Verhalten in solch einem Fall --> UB.
@drgreenthumb sagte in [Anfänger] Funktion schreiben für Falscheingaben:
@swordfish sagte in [Anfänger] Funktion schreiben für Falscheingaben:
[strtod] Also nochmal umständlicher. Fehlerhafte Eingaben lassen sich bei strtod() nicht von der Eingabe von 0 unterscheiden.
Doch, über den endptr:
If no conversion can be performed, 0 is returned and *str_end is set to str
Stimmt. Sorry.
-
Muesste man erstmal wissen, was Falscheingabe genau bedeutet. 1.0 ist falsch? Oder 007? Oder eine Schreibweise mit Exponent? Und sagt er immer den gleichen Fehler, oder erklaert er auch genau was falsch ist? Verhindert er direkt das ich Punkt eintippe oder reagiert er erst nach Druck auf Enter? Allgemein wäre http://en.cppreference.com/w/cpp/string/byte/isdigit ein Ansatzpunkt, kann allein aber auch nicht alles abfangen.
-
@swordfish sagte in [Anfänger] Funktion schreiben für Falscheingaben:
http://www.cplusplus.com/reference/cstdlib/atoi/ und der Standard sagt nichts über das Verhalten in solch einem Fall --> UB.
Was der Standard sagt weiß ich nicht, aber Dein Link widerspricht Dir auch:
The string can contain additional characters after those that form the integral number, which are ignored and have no effect on the behavior of this function.
If the first sequence of non-whitespace characters in str is not a valid integral number, or if no such sequence exists because either str is empty or it contains only whitespace characters, no conversion is performed and zero is returned.
D.h. demnach ist die einzige Möglichkeit UB zu erzeugen, wenn die geparste Nummer zu groß ist um in den int zu passen.
Das mit dem UB ist natürlich mal wieder typischer C/++-Mist vom Feinsten, aber ganz so schlimm wie Du meinst, ist es dann doch nicht.Deine Beispiele zu cin und scanf wären sicher auch eine passende Antwort direkt auf die Ausgangsfrage gewesen, aber wo wir jetzt schon so tief in der Diskussion sind, hier noch ein Beispiel warum ich bei interaktiven Eingaben (ehrlich gesagt bei allen Eingaben) das Parsen ungerne den Stream-Funktionen überlasse:
#include <iostream> using namespace std; int main() { int x, y; cout << "input1:" << endl; if (!(cin >> x)) cout << "error1" << endl; cout << "input2:" << endl; if (!(cin >> y)) cout << "error2" << endl; cout << "Danke: " << x << " und " << y << endl; }
Eingabe:
~$ ./a.out input1: 1.2 input2: error2 Danke: 1 und 0
-
@drgreenthumb sagte in [Anfänger] Funktion schreiben für Falscheingaben:
hier noch ein Beispiel warum ich bei interaktiven Eingaben (ehrlich gesagt bei allen Eingaben) das Parsen ungerne den Stream-Funktionen überlasse
Wenn Du weißt, dass der Eingabestrom im Fehlerzustand ist und Du dann das Eingelesene trotzdem auswertest bist Du doch selbst schuld.
-
@swordfish sagte in [Anfänger] Funktion schreiben für Falscheingaben:
Wenn Du weißt, dass der Eingabestrom im Fehlerzustand ist und Du dann das Eingelesene trotzdem auswertest bist Du doch selbst schuld.
Die Fehlerhafte Eingabe ist halt schon bei input1, wird aber erst bei input2 erkannt.
Du kannst in dem Beispiel ja auch "1 2" eingeben, dann tritt gar kein Fehler auf. Mir gings dabei darum, dass nicht bis zum Newline gelesen wird. Kann man jetzt natürlich als Bug oder Feature betrachten.Ich bleibe dabei: atoi oder strtod ist für sowas besser.
-
@drgreenthumb sagte in [Anfänger] Funktion schreiben für Falscheingaben:
Mir gings dabei darum, dass nicht bis zum Newline gelesen wird.
#include <iostream> #include <cctype> std::istream& swallow_whitespace(std::istream & is) { char ch; while (is && std::isspace(ch = is.get ()) && ch != '\n'); if (ch != '\n') is.setstate (std::ios::badbit); return is; } int main() { int value; if( !( std::cin >> value >> swallow_whitespace ) ) std::cerr << "Error!\n"; }
-
ähm, ja. Das man auch Zeichenweise aus einem Stream lesen kann, ist bekannt.
Oder halt einfach getline & strtod
-
Zeig mal code wenn dass Ergebnis ein
int
sein soll und dann schauen wir, was kürzer und lesbarer ist.
-
string str; getline (cin, str); char* endptr; double d = strtod (&str[0], &endptr); bool ok = !str.empty() && endptr - &str[0] == str.size() && d - (int)d == 0;