Ich bin ein Autodidakt. Ich habe vor ungefähr 1,5 Jahren angefangen zu programmieren. Jetzt habe ich angefangen, Programmierunterricht in der Schule zu haben. Wir haben Programmierkurse für 1/2 Jahr und werden jetzt noch 1/2 haben.
In den Klassen lernen wir, in C ++ zu programmieren (eine Sprache, die ich bereits gut kannte, bevor wir anfingen).
Ich hatte während dieses Kurses keine Schwierigkeiten, aber es gibt ein wiederkehrendes Problem, für das ich keine klare Lösung finden konnte.
Das Problem ist wie folgt (im Pseudocode):
do something
if something failed:
handle the error
try something (line 1) again
else:
we are done!
Hier ist ein Beispiel in C ++
Der Code fordert den Benutzer auf, eine Nummer einzugeben, bis die Eingabe gültig ist. Hiermit wird cin.fail()
überprüft, ob die Eingabe ungültig ist. Wann cin.fail()
ist true
muss ich anrufen cin.clear()
und der cin.ignore()
Lage sein, weiterhin eine Eingabe von dem Strom zu bekommen.
Mir ist bekannt, dass dieser Code nicht überprüft
EOF
. Von den Programmen, die wir geschrieben haben, wird nicht erwartet, dass sie dies tun.
So habe ich den Code in einer meiner Aufgaben in der Schule geschrieben:
for (;;) {
cout << ": ";
cin >> input;
if (cin.fail()) {
cin.clear();
cin.ignore(512, '\n');
continue;
}
break;
}
Mein Lehrer sagte, dass ich das nicht benutzen sollte break
und continue
mag. Er schlug vor, stattdessen eine reguläre Schleife while
oder eine do ... while
Schleife zu verwenden.
Es scheint mir, dass die Verwendung von break
und continue
der einfachste Weg ist, diese Art von Schleife darzustellen. Ich habe tatsächlich eine ganze Weile darüber nachgedacht, aber nicht wirklich eine klarere Lösung gefunden.
Ich denke, er wollte, dass ich so etwas mache:
do {
cout << ": ";
cin >> input;
bool fail = cin.fail();
if (fail) {
cin.clear();
cin.ignore(512, '\n');
}
} while (fail);
Für mich scheint diese Version viel komplexer zu sein, da wir jetzt auch eine Variable haben, die aufgerufen wird fail
, um den Überblick zu behalten, und die Überprüfung auf Eingabefehler zweimal statt nur einmal durchgeführt wird.
Ich dachte mir auch, dass ich den Code so schreiben kann (Missbrauch der Kurzschlussauswertung):
do {
cout << ": ";
cin >> input;
if (fail) {
cin.clear();
cin.ignore(512, '\n');
}
} while (cin.fail() && (cin.clear(), cin.ignore(512, '\n', true);
Diese Version funktioniert genau wie die anderen. Es wird nicht verwendet break
oder continue
und der cin.fail()
Test wird nur einmal durchgeführt. Es erscheint mir jedoch nicht richtig, die "Kurzschlussbewertungsregel" so zu missbrauchen. Ich glaube auch nicht, dass es meinem Lehrer gefallen würde.
Dieses Problem betrifft nicht nur die cin.fail()
Überprüfung. Ich habe break
und continue
mag dies für viele andere Fälle, in denen ein Satz von Codes wiederholt wird, bis eine Bedingung erfüllt ist, bei der auch etwas getan werden muss, wenn die Bedingung nicht erfüllt ist (wie das Aufrufen cin.clear()
und cin.ignore(...)
aus dem cin.fail()
Beispiel).
Ich habe break
und continue
während des gesamten Kurses weiter verwendet und jetzt hat mein Lehrer aufgehört, sich darüber zu beschweren.
Was ist deine Meinung dazu?
Glaubst du, mein Lehrer hat recht?
Kennen Sie einen besseren Weg, um diese Art von Problem darzustellen?
quelle
while (true)
und sofort annehmen , dass es einbreak
,return
oderthrow
irgendwo da drin. Die Einführung einer zusätzlichen Variablen, die im Auge behalten werden muss, um einerbreak
oder auszuweichen,continue
ist kontraproduktiv. Ich würde argumentieren, dass das Problem mit dem Anfangscode darin besteht, dass die Schleife eine Iteration normalerweise nie beendet und dass Sie wissen müssen, dass es eincontinue
Inneres gibt, umif
zu wissen, dass dasbreak
nicht genommen wird.dataIsValid
ist veränderlich. Um zu wissen, dass die Schleife korrekt beendet wird, muss ich überprüfen, ob sie gesetzt ist, wenn die Daten gültig sind, und ob sie zu keinem Zeitpunkt danach deaktiviert wird . In einer Schleife der Formdo { ... if (!expr) { break; } ... } while (true);
weiß ich, dass bei einerexpr
Auswertungfalse
die Schleife unterbrochen wird , ohne dass der Rest des Schleifenkörpers betrachtet werden muss.Antworten:
Ich würde die if-Anweisung etwas anders schreiben, also wird sie genommen, wenn die Eingabe erfolgreich ist.
Es ist auch kürzer.
Was auf einen kürzeren Weg hindeutet, der Ihrem Lehrer gefallen könnte:
quelle
break
am Ende keine benötige . Das allein macht den Code viel einfacher zu lesen. Ich wusste auch nicht, dass!(cin >> input)
das gültig ist. Danke für die Information!cout << ": ";
, wodurch das DRY-Prinzip verletzt wird. Für Code aus der realen Welt wäre dies ein No-Go, da er fehleranfällig wird (wenn Sie diesen Teil später ändern müssen, müssen Sie sicherstellen, dass Sie nicht vergessen, jetzt zwei Zeilen auf ähnliche Weise zu ändern). Trotzdem habe ich dir für deine erste Version eine +1 gegeben, was meiner Meinung nach ein Beispiel für diebreak
richtige Verwendung ist.cout << ": "
vollständig entfernen und nichts würde brechen.while
Befehl besser aussieht".Was Sie anstreben müssen, ist die Vermeidung von Rohschleifen .
Verschieben Sie die komplexe Logik in eine Hilfsfunktion, und plötzlich sind die Dinge viel klarer:
quelle
getValidUserInput
es mehrmals und nicht nur einmal aufgerufen wird. Ich gebe dir +1 dafür, aber ich werde stattdessen Sjoerds Antwort akzeptieren, weil ich finde, dass sie meine Frage besser beantwortet.Es ist nicht so sehr
for(;;)
schlecht. Es ist einfach nicht so klar wie Muster wie:Oder wie Sjoerd es ausdrückte:
Betrachten wir das primäre Publikum für dieses Zeug als Ihre Programmierkollegen, einschließlich der zukünftigen Version von Ihnen, die sich nicht mehr daran erinnert, warum Sie die Pause am Ende so durchgehalten oder die Pause mit dem Fortfahren übersprungen haben. Dieses Muster aus Ihrem Beispiel:
... erfordert ein paar Sekunden zusätzlichen Denkens, um im Vergleich zu anderen Mustern zu simulieren. Es ist keine feste Regel, aber das Überspringen der break-Anweisung mit dem Fortsetzen fühlt sich chaotisch oder klug an, ohne nützlich zu sein, und das Setzen der break-Anweisung am Ende der Schleife, selbst wenn es funktioniert, ist ungewöhnlich. Normalerweise werden beide
break
undcontinue
verwendet, um die Schleife oder diese Iteration der Schleife vorzeitig zu evakuieren, sodass es sich etwas seltsam anfühlt, wenn Sie am Ende eine der beiden Schleifen sehen, auch wenn dies nicht der Fall ist.Davon abgesehen gute Sachen!
quelle
s answer: using a
während die Schleife auf diese Weise zu unnötiger Codeduplizierung für das gegebene Beispiel führen kann. Und das ist ein Problem, das meiner Meinung nach mindestens genauso wichtig ist wie die allgemeine Lesbarkeit der Schleife.while
, halte ich das Bit "nur auf den ersten Blick" für ungerechtfertigt .while
Syntax zahlen . Ich mag es nicht, etwas vor der Schleife zu tun, die auch innerhalb der Schleife ausgeführt wird. Andererseits mag ich auch keine Schleife, die sich in Knoten bindet und versucht, das Präfix umzugestalten. So oder so ein Balanceakt.Mein Logiklehrer in der Schule sagte immer und schlug mir ins Gehirn, dass es nur einen Eingang und einen Ausgang für Schleifen geben sollte. Wenn nicht, erhalten Sie Spaghetti-Code und wissen nicht, wohin der Code während des Debuggens geht.
Im wirklichen Leben denke ich, dass die Lesbarkeit von Code wirklich wichtig ist, damit jemand anderes ein Problem mit Ihrem Code beheben oder debuggen muss, was für ihn einfach ist.
Wenn es sich um ein Leistungsproblem handelt, weil Sie diesen Look millionenfach durchlaufen, ist die for-Schleife möglicherweise schneller. Testen würde diese Frage beantworten.
Ich kenne C ++ nicht, aber ich habe die ersten beiden Ihrer Codebeispiele vollständig verstanden. Ich gehe davon aus, dass continue bis zum Ende der for-Schleife geht und diese dann erneut wiederholt. Das while-Beispiel habe ich vollständig verstanden, aber für mich war es einfacher zu verstehen als Ihr for (;;) - Beispiel. Beim dritten musste ich einige Gedanken machen, um es herauszufinden.
Also ging für mich vorbei, was einfacher zu lesen war (ohne C ++ zu kennen) und was mein Logiklehrer sagte, ich würde die while-Schleife eins verwenden.
quelle
Für mich ist die einfachste C-Übersetzung des Pseudocodes
Ich verstehe nicht, warum diese offensichtliche Übersetzung ein Problem ist.
vielleicht das:
das sieht einfacher aus.
quelle