Visual Basic .NET: Einfache Schleifen

Aus Wikibooks
Zur Navigation springen Zur Suche springen

Vielfach soll ein Programm eine bestimmte Aufgabe nicht nur einmal, sondern mehrmals hintereinander ausführen, bis eine bestimmte Bedingung eintritt. Zum Beispiel wird ein Browser immer wieder versuchen, sich mit einem Webserver zu verbinden, bis dieser die Verbindung annimmt und die gewünschten Daten sendet. Ein Mediaplayer wird, wenn entsprechend eingestellt, eine Wiedergabe solange wiederholen, wie der Benutzer nicht auf den Stoppknopf drückt.

Auch Visual Basic .NET verfügt über eine Möglichkeit, bestimmte Befehle oder Befehlsgruppen zu wiederholen, die Schleifen. Diese unterteilen sich in kopfgesteuerte und fußgesteuerte Schleifen. Beide Arten werden jedoch von einer Anweisung erzeugt, der Do-Loop-Anweisung.

Als Beispiel soll uns dieses Mal ein wirklich praktisches Problem dienen. Nehmen Sie an, Sie haben 1000 € gespart und möchten diese jetzt für 5 Jahre anlegen. Der Berater bei der Bank hat Ihnen folgende zwei Angebote gemacht: ein Sparbuch mit einer Laufzeit von 5 Jahren und einem Jahreszins von 3 % oder eines mit der gleichen Laufzeit, aber einem Monatszins von 0,25 %. Auf den ersten Blick scheinen die Angebote aufs Gleiche hinauszulaufen, denn 0.25 * 12 = 3, doch soll ein Programm klären, was besser ist. Die Tabelle unten stellt die Konditionen noch einmal genauer dar. (Eine Anmerkung: Ich weiß, dass Sparbücher heute veraltet sind und es viel bessere Anlagen gibt, außerdem ist der Zinssatz utopisch, aber das ist schließlich nur ein Beispiel.)

Angebot Art Laufzeit Zins Verzinsung
1 Sparbuch 5 Jahre 3 % jährlich
2 0,25 % monatlich

Fußgesteuerte Schleifen[Bearbeiten]

Eine Do-Loop-Anweisung zur Erstellung einer Schleife besteht aus einer Befehlsgruppe, die zwischen den Schlüsselwörtern Do und Loop notiert wird. Das folgende Beispiel gibt fortwährende Meldungen aus. (Ich empfehle nicht, dieses Beispiel praktisch auszuprobieren.)

Crystal Clear app terminal.png Code:  

Do
    Console.WriteLine("Schleife")
Loop

Crystal Clear app kscreensaver.png Ausgabe:  

Schleife
Schleife
...

Sollten Sie doch so wagemutig sein und das Beispiel ausprobieren, wird Ihnen das Problem mit dieser Variante klar werden. Die Schleife sorgt dafür, dass unendlich viele Meldungen ausgegeben werden, da ja die Befehlsgruppe in der Schleife unendlich oft wiederholt wird. (Zumindest theoretisch, für unendlich viele Ausführungen fehlt uns aber jetzt die Zeit.) Wir haben es hier mit einer Endlosschleife zu tun. (Sie werden in der Praxis feststellen, dass Endlosschleifen manchmal ganz nützlich sind.) Das Problem ist: Wie kriegen wir unsere Schleife dazu, nach einer bestimmten Zeit abzubrechen, zum Beispiel nach 10 Meldungen? Das geht mit einer Bedingung, so wie wir sie in der If-Anweisung verwendet haben. Dazu wird hinter dem Loop das Schlüsselwort Until notiert, gefolgt von der Bedingung. Die Bedingung heißt Abbruchbedingung, denn wenn sie True ist, wird die Ausführung der Schleife abgebrochen.

Crystal Clear app terminal.png Code:  

Do
    Console.WriteLine("Schleife")
Loop Until ...

Damit wird ein neues Problem deutlich: Wie können wir jetzt die 10 Meldungen ausgeben und danach abbrechen? Die Lösung ist eine Zählvariable. Jedes Mal, wenn eine Meldung ausgegeben wird, wird der Zähler um eins erhöht. Sobald der Zähler den Wert 10 erreicht hat, wird die Schleife abgebrochen. Die Implementation (die programmiererische Umsetzung dieses Konzepts) sieht so aus:

Crystal Clear app terminal.png Code:  

Dim Zähler As Integer = 0
Do
    Console.WriteLine("Schleife")
    Zähler += 1
Loop Until Zähler = 10

Crystal Clear app kscreensaver.png Ausgabe:  

Schleife (zehnmal hintereinander)

Am Anfang wird der Zähler erzeugt und mit 0 initialisiert. In der Schleife wird jedes Mal, wenn eine Meldung ausgegeben wird, der Zähler um eins erhöht. Die Abbruchbedingung lautet Zähler = 10, d.h. wenn der Zähler den Wert 10 hat, wird die Ausführung der Schleife abgebrochen und mit den evtl. auf die Schleife folgenden Befehlen fortgesetzt.

Mit dem nun erworbenen Wissen können wir auch die Zinsrechnung implementieren. Auf einer Variable speichern wir zunächst das Startkapital von 1000 €. (Wir verwenden wegen der Centbeträge Gleitkommazahlen.) Nun wird ein Zähler angelegt. Jedes Mal, wenn eine Zinszahlung erfolgt (in diesem Fall simuliert wird), wird der Zähler erhöht. Da wir bereits wissen, wie oft verzinst wird (beim Angebot 1 fünfmal, beim Angebot 2 sechzigmal, denn 60 = 5 * 12), können wir mit einer Gleichheitsoperation eine einfache Abbruchbedingung formulieren. Nachfolgend der Code für die Berechnung des 1. Angebotes:

Crystal Clear app terminal.png Code:  

Dim Kapital As Single = 1000.0 'Startkapital
Dim AnzahlVerzinsungen As Integer = 0 'Zähler mit beschreibendem Namen
Do
    Kapital += 0.03 * Kapital
    AnzahlVerzinsungen += 1
Loop Until AnzahlVerzinsungen = 5
Console.WriteLine("Am Ende haben Sie " & Kapital & " Euro.")

Crystal Clear app kscreensaver.png Ausgabe:  

Am Ende haben Sie 1159.2740743 Euro.

Die eigentliche Berechnung läuft in der Zeile Kapital += 0.03 * Kapital ab. Der Ausdruck rechts des Kompositoperatoren += ist der Zins, nämlich 3 % (= 3/100 = 0,03) des aktuellen Kapitals. Dieser Zins wird dem Kapital hinzugerechnet, also auf das Sparbuchkonto gutgeschrieben. Beachten Sie nach der Schleife außerdem den Aufruf der Console.WriteLine-Funktion. Für die Verkettungsoperation wird die Gleitkommazahlvariable Kapital in eine String-Variable umgewandelt.

Sie sollten als Ergebnis etwa 1159 Euro erhalten. Wenn Sie die vielen Nachkommastellen in der Ausgabe stören, ersetzen Sie in der letzten Zeile das Kapital zwischen den zwei Verkettungsoperatoren durch Math.Round(Kapital,2). Dieser Aufruf der Round-Funktion des Math-Objektes rundet die Zahl auf zwei Nachkommastellen.

Als Übung sollten Sie jetzt versuchen, ausgehend von dieser Beispielimplementierung des 1. Angebotes eine Rechnung für das 2. Angebot durchzuführen. Beachten Sie den veränderten Zinssatz von 0,25 % sowie die größere Anzahl von Verzinsungen, da nicht 5 Jahre lang, sondern 60 Monate lang verzinst wird. Zur Kontrolle: Mit 1162 Euro ist das 2. Angebot minimal besser als das erste. Das liegt daran, dass die Zinsen öfter mitverzinst werden.

Man kann Schleifen auch nicht nur mit Zählern verwenden, sondern auch komplexere Sachverhalte sehr einfach und ressourcensparend implementieren. Ein Beispiel: Sie haben sich für das 1. Angebot entschieden, also die jährliche Verzinsung mit 3%, und wollen jetzt wissen, wie lange Sie warten müssen, bis sich 100 Euro Zinsen angesammelt haben.

Den Zähler werden wir in unserem Entwurf weiterverwenden, allerdings in einem etwas anderem Kontext. Jetzt wird er nicht mehr für die Abbruchbedingung, sondern für die Feststellung des Ergebnisses, nämlich wieviele Jahre das Ansparen von 100 Euro dauert, verwendet. Der Abbruch der Schleife erfolgt, sobald das gewünschte Sparziel von 100 Euro erreicht ist, also das Kapital über 1100 Euro gewachsen ist. Die Abbruchbedingung ist also Kapital >= 1100.0.

Versuchen Sie einmal, anhand dieser Überlegungen das entsprechende Programm zu implementieren. Die Ausgabe sollte die Wartezeit sowie die Endsumme beinhalten. (Diese beiden Fakten können Sie auch auf zwei Hinweisfelder aufteilen.) Die Lösung sehen Sie unten.

Crystal Clear app terminal.png Code:  

Dim Kapital As Single = 1000.0 'Startkapital
Dim Jahreszahl As Integer = 0
Do
    Kapital += 0.03 * Kapital
    Jahreszahl += 1
Loop Until Kapital >= 1100.0
Console.Write("Sie müssen " & Jahreszahl & " Jahre warten. ")
Console.WriteLine("Am Ende haben Sie " & Kapital & " Euro.")

Crystal Clear app kscreensaver.png Ausgabe:   Sie müssen 4 Jahre warten. Am Ende haben Sie 1125,509 Euro.

Kopfgesteuerte Schleifen[Bearbeiten]

Mit Until kann man nach der Ausführung der Schleife eine Bedingung prüfen und die Schleife eventuell wiederholen. Da die Bedingung am Fuß der Schleife sitzt, heißt diese Schleifenart „fußgesteuerte Schleife“.

Das genaue Gegenteil ist die „kopfgesteuerte Schleife“. Hier steht die Bedingung vor der Schleife. Nur wenn die Bedingung True ist, wird die Schleife ausgeführt. Wenn nicht, springt die Ausführung an das Ende der Schleife.

Eine kopfgesteuerte Schleife wird in Visual Basic .NET über das Schlüsselwort While erzeugt. Es wird nach Do notiert, gefolgt von der Fortsetzungsbedingung, dem Gegenstück zur Abbruchbedingung. Schon der Name zeigt, wie gegensätzlich sich beide Bedingungen verhalten. Die kopfgesteuerte Schleife wird erneut ausgeführt, wenn die Fortsetzungsbedingung True ist, die fußgesteuerte Schleife wird erneut ausgeführt, wenn die Abbruchbedingung False ist. Darauf müssen Sie auch achten, wenn sie eine fuß- durch eine kopfgesteuerte Schleife ersetzen oder umgekehrt. Das folgende Beispiel ist zum letzen Code äquivalent. Achten Sie besonders auf die Fortsetzungsbedingung.

Crystal Clear app terminal.png Code:  

Dim Kapital As Single = 1000.0 'Startkapital
Dim Jahreszahl As Integer = 0
Do While Kapital < 1100.0
    Kapital += 0.03 * Kapital
    Jahreszahl += 1
Loop
Console.Write("Sie müssen " & Jahreszahl & " Jahre warten. ")
Console.WriteLine("Am Ende haben Sie " & Kapital & " Euro.")

Crystal Clear app kscreensaver.png Ausgabe:   Sie müssen 4 Jahre warten. Am Ende haben Sie 1125,509 Euro.

Beachten Sie, dass sich die While- und Until-Konstrukte gegenseitig ausschließen. Das heißt, dass eine Schleife entweder kopf- oder fußgesteuert ist.

Grundsätzlich stellt sich nun die Frage, wann eine kopfgesteuerte Schleife und wann eine fußgesteuerte Schleife eingesetzt werden sollte. Dazu muss man sich folgendes klarmachen: Eine fußgesteuerte Schleife wird mindestens einmal ausgeführt, da die Bedingung erst nach der ersten Ausführung getestet wird. Bei einer kopfgesteuerten Schleife kann es sein, dass, wenn die Fortsetzungsbedingung das erste Mal nicht erfüllt ist, die Schleife nie ausgeführt wird.

Daher: Verwenden Sie fußgesteuerte Schleifen, wenn Sie sicherstellen müssen, dass die Schleife mindestens einmal ausgeführt wird. Verwenden Sie kopfgesteuerte Schleifen, wenn Sie sich nicht sicher sind, ob die Schleife überhaupt ausgeführt werden muss.

Sollte diese Faustregel keine Entscheidung liefern, rate ich Ihnen zur fußgesteuerten Schleife, da diese ein bisschen schneller ausgeführt wird.

Exit Do und Continue Do[Bearbeiten]

Eben sagte ich, dass eine Schleife entweder kopf- oder fußgesteuert ist. Das stimmt so nicht. Eine Schleife kann auch weder kopf- noch fußgesteuert sein. Es handelt sich dann um eine der bereits oben angesprochenen Endlosschleifen.

Doch auch diese Schleifen werden nicht notwendigerweise unendlich oft ausgeführt. Der Grund ist die Exit-Do-Anweisung. Diese Anweisung, die innerhalb jeder Do-Schleife vorkommen kann, sorgt dafür, dass die Schleife sofort verlassen wird. Dabei werden auch die Bedingungen der While- und Until-Konstrukte übergangen. Die Schleife wird nach der Exit-Do-Anweisung nicht mehr ausgeführt.

Wie If-Anweisungen kann man Do-Schleifen verschachteln. Führt man in einer Verschachtelung von Do-Schleifen die Exit-Do-Anweisung aus, so wird nur die innerste Schleife verlassen. Im folgenden Beispiel springt die Ausführung nach der Exit-Do-Anweisung zur Anweisung Console.WriteLine("3").

Crystal Clear app terminal.png Code:  

Dim Zähler As Integer = 0
Do
    Console.WriteLine("1")
    Do
        Exit Do
        Console.WriteLine("2")
    Loop
    Console.WriteLine("3")
    Zähler += 1
Loop Until Zähler = 2

Crystal Clear app kscreensaver.png Ausgabe:  

1 
3
1
3

Des Weiteren gibt es die Continue-Do-Anweisung. Sie wirkt ähnlich wie Exit Do, jedoch springt sie an den Anfang der Schleife. Ist die Schleife Kopfgesteuert, wird auch die Bedingung geprüft, bevor die Ausführung weitergeht.

Optimierungen[Bearbeiten]

Ich möchte noch einmal auf das erste Beispiel Bezug nehmen. Die eigentliche Berechnung ist hier nämlich ziemlich unvorteilhaft implementiert. In den folgenden Zeilen wird der Befehl schrittweise umgeformt, um am Ende einen effektiveren Befehl, der weniger Operationen enthält, zu erhalten. Jede einzelne Codezeile tut dabei das gleiche, nur auf unterschiedliche Arten.

Crystal Clear app terminal.png Code:  

Kapital += 0.03 * Kapital               'Ausgangssituation: 2 Operationen
Kapital = Kapital + 0.03 * Kapital
Kapital = 1 * Kapital + 0.03 * Kapital
Kapital = (1 + 0.03) * Kapital
Kapital = 1.03 * Kapital
Kapital *= 1.03                         'Endsituation: 1 Operation

Das ist ein schönes Beispiel, wie mit einfachen Überlegungen die Ausführungsgeschwindigkeit und der Speicherverbrauch eines Programmes reduziert werden können. Dies macht sich vor allem bei zeitkritischen Anwendungen und hohen Wiederholungsraten bemerkbar (etwa, wenn Sie einmal probieren, was auf dem Sparbuch nach 100.000 Jahren theoretisch passiert wäre), ist aber auch ein Zeichen eines eleganten, umsichtigen Programmierstils.

Crystal Clear app terminal.png Code:  

Dim Kapital As Single = 1000.0 'Startkapital
Dim AnzahlVerzinsungen As Integer = 0 'Zähler mit beschreibendem Namen
Do
    Kapital *= 1.03
    AnzahlVerzinsungen += 1
Loop Until AnzahlVerzinsungen = 5
Console.WriteLine("Am Ende haben Sie " & Kapital & " Euro.")

Man kann das Beispiel noch weiter vereinfachen, wenn man bedenkt, dass die Potenzierung nur eine Verkettung von Multiplikationen ist. In diesem Fall wird das Kapital fünfmal hintereinander mit 1.03 multipliziert, was einer Multiplikation mit 1.03 hoch 5 gleichkommt. Die Schleife und die Variable Kapital sind nun nicht mehr nötig, das Beispiel verkürzt sich in der Gesamtheit von sieben Zeilen auf eine:

Crystal Clear app terminal.png Code:  

Console.WriteLine("Am Ende haben Sie " & 1000.0 * (1.03 ^ 5) & " Euro.")