Mögliche Duplikate:
While vs. Do While
Wann sollte ich do-while anstelle von while-Schleifen verwenden?
Ich programmiere jetzt schon eine Weile (2 Jahre Arbeit + 4,5 Jahre Abschluss + 1 Jahr Pre-College), und ich habe noch nie eine Do-While-Schleife verwendet, zu der ich im Kurs Einführung in die Programmierung nicht gezwungen wurde. Ich habe das wachsende Gefühl, dass ich falsch programmiere, wenn ich nie auf etwas so Grundlegendes stoße.
Könnte es sein, dass ich einfach nicht auf die richtigen Umstände gestoßen bin?
Was sind einige Beispiele, bei denen es notwendig wäre, ein Do-While anstelle eines While zu verwenden?
(Meine Schulausbildung war fast ausschließlich in C / C ++ und meine Arbeit ist in C #. Wenn es also eine andere Sprache gibt, in der dies absolut sinnvoll ist, weil Do-Whiles anders funktionieren, gelten diese Fragen nicht wirklich.)
Zur Verdeutlichung ... Ich kenne den Unterschied zwischen a while
und a do-while
. Während prüft die Ausgangsbedingung und führt dann Aufgaben aus. do-while
führt Aufgaben aus und überprüft dann die Beendigungsbedingung.
Antworten:
Wenn Sie immer möchten, dass die Schleife mindestens einmal ausgeführt wird. Es ist nicht üblich, aber ich benutze es von Zeit zu Zeit. Ein Fall, in dem Sie es möglicherweise verwenden möchten, ist der Versuch, auf eine Ressource zuzugreifen, für die möglicherweise ein erneuter Versuch erforderlich ist, z
quelle
do-while ist besser, wenn der Compiler nicht in der Optimierung kompetent ist. do-while hat nur einen einzigen bedingten Sprung, im Gegensatz zu for und while, die einen bedingten Sprung und einen bedingungslosen Sprung haben. Bei CPUs, die über Pipelines verfügen und keine Verzweigungsvorhersage durchführen, kann dies einen großen Unterschied in der Leistung einer engen Schleife bewirken.
Da die meisten Compiler intelligent genug sind, um diese Optimierung durchzuführen, werden normalerweise alle im dekompilierten Code gefundenen Schleifen ausgeführt (wenn der Dekompiler überhaupt die Mühe hat, Schleifen aus rückwärts gerichteten lokalen Gotos zu rekonstruieren).
quelle
Ich habe dies in einer TryDeleteDirectory-Funktion verwendet. Es war so etwas
quelle
while
?Do while ist nützlich, wenn Sie etwas mindestens einmal ausführen möchten. Nehmen wir als gutes Beispiel für die Verwendung von do while vs. while an, dass Sie Folgendes erstellen möchten: Ein Taschenrechner.
Sie können dies erreichen, indem Sie eine Schleife verwenden und nach jeder Berechnung prüfen, ob die Person das Programm beenden möchte. Jetzt können Sie wahrscheinlich davon ausgehen, dass die Person dies nach dem Öffnen des Programms mindestens einmal tun möchte, damit Sie Folgendes tun können:
quelle
continue
ist ein Schlüsselwort; D== true
wird nicht gebraucht.cont == true
Wenn cont wahr ist, wird true zurückgegeben. Das ist völlig nutzlos.Dies ist eine Art indirekte Antwort, aber diese Frage brachte mich dazu, über die Logik dahinter nachzudenken, und ich dachte, dies könnte es wert sein, geteilt zu werden.
Wie alle anderen gesagt haben, verwenden Sie eine
do ... while
Schleife, wenn Sie den Body mindestens einmal ausführen möchten. Aber unter welchen Umständen möchten Sie das tun?Nun, die offensichtlichste Klasse von Situationen, an die ich denken kann, ist, wenn der anfängliche ("nicht grundierte") Wert der Prüfbedingung der gleiche ist wie beim Beenden . Dies bedeutet, dass Sie den Schleifenkörper einmal ausführen müssen, um die Bedingung auf einen nicht existierenden Wert vorzubereiten, und dann die eigentliche Wiederholung basierend auf dieser Bedingung ausführen müssen. Da Programmierer so faul sind, hat sich jemand entschlossen, dies in eine Kontrollstruktur einzubinden.
So kann beispielsweise das Lesen von Zeichen von einer seriellen Schnittstelle mit Zeitüberschreitung die folgende Form annehmen (in Python):
Beachten Sie die Vervielfältigung des Codes :
char_read = port.read(1)
. Wenn Python einedo ... while
Schleife hätte, hätte ich vielleicht verwendet:Der zusätzliche Vorteil für Sprachen, die einen neuen Bereich für Schleifen erstellen:
char_read
Verschmutzt den Funktionsnamespace nicht. Beachten Sie aber auch, dass es einen besseren Weg gibt, dies zu tun, und zwar unter Verwendung des Python-None
Werts:Hier ist der Kern meines Punktes: In Sprachen mit nullbaren Typen tritt die Situation
initial_value == exit_value
weitaus seltener auf, und das kann der Grund sein, warum Sie nicht darauf stoßen. Ich sage nicht, dass es nie passiert, weil es immer noch Zeiten gibt, in denen eine Funktion zurückkehrtNone
, um eine gültige Bedingung anzuzeigen. Aber meiner eiligen und kurz überlegten Meinung nach würde dies viel mehr passieren, wenn die von Ihnen verwendeten Sprachen keinen Wert zulassen, der bedeutet: Diese Variable wurde noch nicht initialisiert.Dies ist keine perfekte Argumentation: In der Realität bilden Nullwerte, da sie nun üblich sind, einfach ein weiteres Element der Menge gültiger Werte, die eine Variable annehmen kann. In der Praxis können Programmierer jedoch unterscheiden, ob sich eine Variable in einem vernünftigen Zustand befindet, der den Schleifenausgangszustand enthalten kann, und sich in einem nicht initialisierten Zustand befindet.
quelle
None
,while
fügt die Version dem Antwortpuffer korrekt nichts hinzu, aber Ihredo
Version fügt immer etwas hinzu.read()
sollte niemals zurückkehrenNone
. Wenn Sie eine Bibliothek dort verwenden, wo dies der Fall ist, gilt die Prämisse nicht (dh, dass der Sentinel-Wert nicht im Satz möglicher Prüfwerte enthalten ist).''
anstattNone
. Eine Art Wert, der als falsch ausgewertet wird. Kreide es auf meine Unkenntnis mit Pythonsread
Funktion.read()
zurückgegeben wird''
, wird nichts an die Zeichenfolge angehängt, sie ist leer.Ich habe sie ein bisschen benutzt, als ich in der Schule war, aber seitdem nicht mehr so oft.
Theoretisch sind sie nützlich, wenn der Schleifenkörper vor der Prüfung der Ausgangsbedingungen einmal ausgeführt werden soll. Das Problem ist, dass ich für die wenigen Fälle, in denen ich die Prüfung nicht zuerst möchte, normalerweise die Exit-Prüfung in der Mitte des Schleifenkörpers und nicht ganz am Ende möchte . In diesem Fall bevorzuge ich es, das Bekannte
for (;;)
mit einemif (condition) exit;
irgendwo im Körper zu verwenden.In der Tat, wenn ich in Bezug auf die Schleifenausgangsbedingung etwas wackelig bin, finde ich es manchmal nützlich, die Schleife
for (;;) {}
bei Bedarf mit einer Exit-Anweisung zu schreiben , und wenn ich fertig bin, kann ich sehen, ob es möglich ist. " bereinigt "durch Verschieben von Initiierungen, Exit-Bedingungen und / oder Inkrementieren von Code in diefor
Klammern.quelle
for(;;)
mit "Endlosschleife" gleichzusetzen , währendwhile(true)
ich innehalten und darüber nachdenken muss. Vielleicht liegt es daran, dass ich C codiert habe, bevor es eine gabtrue
. Früher hatten wir nurTRUE
ein Makro, und wenn etwas fehlerhaft war, musste ich mich davon überzeugen, dass das Makro nicht0
irgendwie neu definiert wurde (es ist passiert!). Damitfor(;;)
gibt es keine Chance. Wenn Sie auf der while-Form bestehen, würde ich es fast lieber sehenwhile (1)
. Natürlich könnten sich einige fragen, ob es nicht der Buchstabe l ist ...codeify
Text einfügt , können Sie ihn einfach selbst direkt in das Kommentarfeld eingeben. Ich habe einige Leute gesehen, die Hyperlinks eingefügt haben, aber das ist mir ein bisschen zu hardcore.Eine Situation, in der Sie einen Code immer einmal und je nach Ergebnis möglicherweise mehrmals ausführen müssen. Das gleiche kann auch mit einer regulären
while
Schleife erzeugt werden.quelle
do while
ist, wenn Sie den Codeblock mindestens einmal ausführen möchten.while
Auf der anderen Seite wird nicht immer abhängig von den angegebenen Kriterien ausgeführt.quelle
So einfach ist das:
Vorbedingung gegen Nachbedingung
Jetzt wo du das Geheimnis kennst ... benutze sie mit Bedacht :)
quelle
Ich sehe, dass diese Frage angemessen beantwortet wurde, möchte aber dieses sehr spezifische Anwendungsfallszenario hinzufügen. Möglicherweise verwenden Sie do ... häufiger.
wird häufig für mehrzeilige #defines verwendet. Beispielsweise:
Dies funktioniert in Ordnung für:
-aber- es gibt ein gotcha für:
da dies erweitert zu:
Wenn Sie es in eine do ... while (0) -Schleife einschließen, wird es ordnungsgemäß zu einem einzelnen Block erweitert:
quelle
Die bisherigen Antworten fassen die allgemeine Verwendung für Do-While zusammen. Das OP hat jedoch nach einem Beispiel gefragt. Hier ist eines: Benutzereingaben abrufen. Die Benutzereingabe ist jedoch möglicherweise ungültig. Sie fordern daher eine Eingabe an, validieren sie, fahren fort, wenn sie gültig ist, oder wiederholen sie.
Mit do-while erhalten Sie die Eingabe, während die Eingabe ungültig ist. Mit einer regulären while-Schleife erhalten Sie die Eingabe einmal, aber wenn sie ungültig ist, erhalten Sie sie immer wieder, bis sie gültig ist. Es ist nicht schwer zu erkennen, dass Ersteres kürzer, eleganter und einfacher zu warten ist, wenn der Körper der Schleife komplexer wird.
quelle
break
wenn die Eingabe korrekt ist.Ich habe es für einen Leser verwendet, der dieselbe Struktur mehrmals liest.
quelle
Hier ist meine Theorie, warum die meisten Leute (einschließlich mir) while () {} Schleifen bevorzugen, um {} while () zu tun: Eine while () {} Schleife kann leicht angepasst werden, um wie eine do..while () Schleife zu funktionieren, während das Gegenteil der Fall ist ist nicht wahr. Eine while-Schleife ist in gewisser Weise "allgemeiner". Auch Programmierer mögen leicht zu erfassende Muster. Eine while-Schleife sagt gleich zu Beginn, was ihre Invariante ist, und das ist eine schöne Sache.
Folgendes meine ich mit der "allgemeineren" Sache. Nehmen Sie diese do..while-Schleife:
Die Umwandlung in eine while-Schleife ist unkompliziert:
Nun nehmen wir eine Modell-while-Schleife:
Und verwandeln Sie dies in eine do..while-Schleife, die diese Monstrosität ergibt:
Jetzt haben wir zwei Überprüfungen an entgegengesetzten Enden und wenn sich die Invariante ändert, müssen Sie sie an zwei Stellen aktualisieren. In gewisser Weise tun .. währenddessen wie die speziellen Schraubendreher im Werkzeugkasten, die Sie nie verwenden, weil der Standard-Schraubendreher alles tut, was Sie brauchen.
quelle
Ich programmiere ungefähr 12 Jahre und erst vor 3 Monaten bin ich auf eine Situation gestoßen, in der es sehr praktisch war, do-while zu verwenden, da immer eine Iteration erforderlich war, bevor eine Bedingung überprüft wurde. Also schätze, deine große Zeit steht vor der Tür :).
quelle
do
while
eine bessere Lösung ohne Reue war?Ich kann mir nicht vorstellen, wie lange Sie ohne
do...while
Schleife gegangen sind .Momentan befindet sich einer auf einem anderen Monitor und es gibt mehrere solcher Schleifen in diesem Programm. Sie haben alle die Form:
quelle
Dies ist meine persönliche Meinung, aber diese Frage bittet um eine erfahrungsbasierte Antwort:
Ich programmiere seit 36 Jahren in C und verwende
do
/while
loop nie in normalem Code.Die einzige überzeugende Verwendung für dieses Konstrukt sind Makros, in denen mehrere Anweisungen über a in eine einzelne Anweisung eingeschlossen werden können
do { multiple statements } while (0)
Ich habe unzählige Beispiele für
do
/while
Schleifen mit falscher Fehlererkennung oder redundanten Funktionsaufrufen gesehen.Meine Erklärung für diese Beobachtung ist, dass Programmierer dazu neigen, Probleme falsch zu modellieren, wenn sie in
do
/while
Schleifen denken . Sie verpassen entweder eine wichtige Endbedingung oder sie vermissen das mögliche Versagen der Anfangsbedingung, die sie zum Ende verschieben.Aus diesen Gründen bin ich zu der Überzeugung gelangt, dass dort
do
while
, wo es eine / -Schleife gibt, ein Fehler vorliegt , und fordere regelmäßig Programmieranfänger auf, mir eindo
/ zu zeigenwhile
gelangt Schleife bei der ich keinen Fehler in der Nähe erkennen kann.Diese Art von Schleife kann leicht vermieden werden: Verwenden Sie a
for (;;) { ... }
und fügen Sie die erforderlichen Terminierungstests hinzu, wo sie angemessen sind. Es ist durchaus üblich, dass es mehr als einen solchen Test geben muss.Hier ist ein klassisches Beispiel:
Dies schlägt fehl, wenn die Datei nicht mit einem Zeilenumbruch endet. Ein triviales Beispiel für eine solche Datei ist die leere Datei.
Eine bessere Version ist diese:
Alternativ verbirgt diese Version auch die
c
Variable:Versuchen Sie zu suchen
while (c != '\n');
in einer Suchmaschine suchen, und Sie werden Fehler wie diesen finden (abgerufen am 24. Juni 2017):In ftp://ftp.dante.de/tex-archive/biblio/tib/src/streams.c hat die Funktion
getword(stream,p,ignore)
eindo
/while
und sicher genug mindestens 2 Fehler:c
ist definiert alschar
undwhile (c!='\n') c=getc(stream);
Fazit: Vermeiden Sie
do
/while
Schleifen und suchen Sie nach Fehlern, wenn Sie einen sehen.quelle
while() {}
Schleifen zu vermeiden , weil sie in Bezug auf anfängliche Überprüfungen sicherer sind, so dass Sie dazu neigen, "Gehirn aus" zu machen, faul über einen besseren Algorithmus nachzudenken, eine Menge unnötiger Fehlerprüfungen durchzuführen usw. "Mangel ando{}while()
Verwendung" ist ein Zeichen von schlechtem (hirnlosem) oder neuem Programmierer, produzieren weniger Qualität und langsameren Code. Also frage ich mich zuerst: "Ist es ein strikter while () {} Fall?" Wenn nicht - ich werde nur versuchen, do while-Schleife zu schreiben, obwohl dies mehr Nachdenken und Genauigkeit der Eingabedaten erfordern könntewhile
Schleifen prüfen den Zustand vor der Schleife,do...while
Schleifen prüfen den Zustand nach der Schleife. Dies ist nützlich, wenn Sie die Bedingung auf Nebenwirkungen der laufenden Schleife stützen möchten oder, wie andere Poster sagten, wenn die Schleife mindestens einmal ausgeführt werden soll.Ich verstehe, woher du kommst, aber das
do-while
ist etwas, das die meisten selten benutzen, und ich habe mich selbst nie benutzt. Du machst es nicht falsch.Du machst es nicht falsch. Das ist so, als würde man sagen, jemand macht es falsch, weil er das
byte
Primitiv nie benutzt hat . Es ist einfach nicht so häufig verwendet.quelle
Ich habe a verwendet,
do while
wenn ich einen Sentinel-Wert am Anfang einer Datei lese, aber ansonsten finde ich es nicht ungewöhnlich, dass diese Struktur nicht allzu häufig verwendet wird -do-while
s sind wirklich situativ.quelle
Das häufigste Szenario, in dem ich eine
do
/while
-Schleife verwende, ist ein kleines Konsolenprogramm, das auf der Grundlage einiger Eingaben ausgeführt wird und so oft wiederholt wird, wie der Benutzer möchte. Offensichtlich macht es keinen Sinn, dass ein Konsolenprogramm keine Zeit ausgeführt wird. aber über das erste Mal hinaus liegt es am Benutzer - daherdo
/while
statt nurwhile
.Auf diese Weise kann der Benutzer bei Bedarf verschiedene Eingaben ausprobieren.
Ich vermute, dass Softwareentwickler heutzutage
do
/while
immer weniger verwenden, da praktisch jedes Programm unter der Sonne eine Art GUI hat. Bei Konsolen-Apps ist dies sinnvoller, da die Ausgabe ständig aktualisiert werden muss, um Anweisungen bereitzustellen oder den Benutzer mit neuen Informationen aufzufordern. Im Gegensatz dazu kann bei einer grafischen Benutzeroberfläche der Text, der dem Benutzer diese Informationen zur Verfügung stellt, einfach auf einem Formular sitzen und muss niemals programmgesteuert wiederholt werden.quelle
Ich verwende ständig Do-While-Schleifen, wenn ich Dateien einlese. Ich arbeite mit vielen Textdateien, die Kommentare in der Kopfzeile enthalten:
Ich werde eine do-while-Schleife verwenden, um bis zur Zeile "column1 column2" zu lesen, damit ich nach der interessierenden Spalte suchen kann. Hier ist der Pseudocode:
Dann mache ich eine while-Schleife, um den Rest der Datei durchzulesen.
quelle
if (line[0]=='#') continue;
direkt nach demread_line
Aufruf in Ihre Haupt-while-SchleifeAls Geezer-Programmierer verwendeten viele meiner Schulprogrammierungsprojekte textmenügesteuerte Interaktionen. Praktisch alle verwendeten so etwas wie die folgende Logik für das Hauptverfahren:
Seit der Schulzeit habe ich festgestellt, dass ich die while-Schleife häufiger benutze.
quelle
Eine der Anwendungen, die ich gesehen habe, ist in Oracle, wenn wir uns Ergebnismengen ansehen.
Sobald Sie eine Ergebnismenge haben, rufen Sie diese zuerst ab (do) und von diesem Punkt an. Überprüfen Sie, ob der Abruf ein Element zurückgibt oder nicht (während das Element gefunden wurde.). Dasselbe gilt möglicherweise für alle anderen " Abrufähnliche "Implementierungen.
quelle
Ich habe es in einer Funktion verwendet, die die nächste Zeichenposition in einer utf-8-Zeichenfolge zurückgegeben hat:
Beachten Sie, dass diese Funktion aus dem Kopf geschrieben und nicht getestet wurde. Der Punkt ist, dass Sie den ersten Schritt sowieso tun müssen und Sie müssen es tun, bevor Sie den Zustand bewerten können.
quelle
*(unsigned char *)txt-0x80U<0x40
.Jede Art von Konsoleneingabe funktioniert gut mit do-while, da Sie das erste Mal dazu auffordern und erneut auffordern, wenn die Eingabevalidierung fehlschlägt.
quelle
Es ist eine weit verbreitete Struktur in einem Server / Verbraucher:
das
REPEAT UNTIL(cond)
Wesen ado {...} while(!cond)
Manchmal kann das Warten auf Arbeit (0) in Bezug auf die CPU günstiger sein (selbst das Eliminieren der Timeout-Berechnung kann bei sehr hohen Ankunftsraten eine Verbesserung darstellen). Darüber hinaus gibt es viele Ergebnisse der Warteschlangentheorie, die die in einer geschäftigen Zeit zugestellte Nummer zu einer wichtigen Statistik machen. (Siehe zum Beispiel Kleinrock - Vol 1.)
Ähnlich:
wo
check for and do other work
es exorbitant teuer sein kann, in die Hauptschleife zu setzen, oder vielleicht ein Kernel, der eine effizientewaitany(waitcontrol*,n)
Operation nicht unterstützt, oder vielleicht eine Situation, in der eine priorisierte Warteschlange die andere Arbeit verhungern lässt und Gas als Hungerkontrolle verwendet wird.Diese Art des Balancierens kann wie ein Hack erscheinen, kann aber notwendig sein. Die blinde Verwendung von Thread-Pools würde die Leistungsvorteile der Verwendung eines Caretaker-Threads mit einer privaten Warteschlange für eine komplizierte Datenstruktur mit hoher Aktualisierungsrate vollständig zunichte machen, da die Verwendung eines Thread-Pools anstelle eines Caretaker-Threads eine thread-sichere Implementierung erfordern würde.
Ich möchte wirklich nicht in eine Debatte über den Pseudocode (zum Beispiel, ob das angeforderte Herunterfahren in UNTIL getestet werden soll) oder über Caretaker-Threads im Vergleich zu Thread-Pools geraten - dies soll nur einen Eindruck von einem bestimmten Anwendungsfall vermitteln die Kontrollflussstruktur.
quelle
Ich bin darauf gestoßen, als ich nach der richtigen Schleife für eine Situation gesucht habe, die ich habe. Ich glaube, dies wird eine häufige Situation vollständig befriedigen, in der eine do .. while-Schleife eine bessere Implementierung ist als eine while-Schleife (C # -Sprache, da Sie angegeben haben, dass dies Ihre primäre Aufgabe für die Arbeit ist).
Ich generiere eine Liste von Zeichenfolgen basierend auf den Ergebnissen einer SQL-Abfrage. Das von meiner Abfrage zurückgegebene Objekt ist ein SQLDataReader. Dieses Objekt verfügt über eine Funktion namens Read (), die das Objekt zur nächsten Datenzeile weiterleitet und true zurückgibt, wenn eine andere Zeile vorhanden war. Es wird false zurückgegeben, wenn keine weitere Zeile vorhanden ist.
Mit diesen Informationen möchte ich jede Zeile an eine Liste zurückgeben und dann anhalten, wenn keine Daten mehr zurückgegeben werden müssen. Eine Do ... While-Schleife funktioniert in dieser Situation am besten, da sie sicherstellt, dass ein Element zur Liste hinzugefügt wird, bevor überprüft wird, ob eine weitere Zeile vorhanden ist. Der Grund, warum dies getan werden muss, bevor das while (Bedingung) überprüft wird, ist, dass es bei der Überprüfung auch voranschreitet. Die Verwendung einer while-Schleife in dieser Situation würde dazu führen, dass die erste Zeile aufgrund der Art dieser bestimmten Funktion umgangen wird.
Zusamenfassend:
Das wird in meiner Situation nicht funktionieren.
Dieser Wille.
quelle
Read()
und sollte eine while-Schleife sein, da der ersteRead()
Aufruf auf die erste Zeile zugreift. Der äußere ruft aufNextResult()
und sollte eine Pause sein, da der erste Ergebnisdatensatz vor dem erstenNextResult()
Aufruf aktiv ist. Die Codefragmente sind wenig sinnvoll, insbesondere weil die Kommentare nicht mit dem Code übereinstimmen und falsch sind.quelle