Menu

C# for-Schleife: Syntax, Rückwärtszählen, verschachtelte Schleifen und Fallen

Wie die for-Schleife in C# funktioniert: Initialisierer, Bedingung und Iterator, rückwärts zählen und Schrittweiten, mehrere Schleifenvariablen, Arrays per Index durchlaufen, verschachtelte Schleifen, for(;;) und die Bugs mit Off-by-one und Entfernen während der Iteration.

Diese Seite enthält ausführbare Editoren - bearbeiten, ausführen und Ausgabe sofort sehen.

Eine for-Schleife wiederholt einen Block, solange eine Bedingung wahr ist, wobei Vorbereitung und Schritt im Schleifenkopf stehen. Sie ist die Schleife fürs Zählen: eine feste Anzahl an Wiederholungen oder jeder Index eines Arrays.

Ausgabe:

Lap 1 of 5
Lap 2 of 5
Lap 3 of 5
Lap 4 of 5
Lap 5 of 5

Wie die drei Teile ablaufen

for (initializer; condition; iterator) läuft in einer festen Reihenfolge ab:

  1. Der Initialisierer (int i = 1) läuft einmal, vor allem anderen.
  2. Die Bedingung (i <= 5) wird geprüft. Ist sie false, endet die Schleife, und der Rumpf läuft nie wieder.
  3. Der Rumpf läuft.
  4. Der Iterator (i++) läuft, dann geht es zurück zu Schritt 2.

Weil die Bedingung vor jedem Durchlauf geprüft wird, kann eine for-Schleife null Mal laufen: for (int i = 10; i < 5; i++) betritt ihren Rumpf nie. Die Schleife oben verhält sich wie diese while-Schleife:

int i = 1;
while (i <= 5)
{
    Console.WriteLine($"Lap {i} of 5");
    i++;
}

Die beiden Formen unterscheiden sich in einem Detail: continue in einem for-Rumpf führt den Iterator trotzdem aus, während es in dieser while-Version i++ überspringen würde. Die Schleife würde dann dasselbe i erneut prüfen und könnte endlos laufen. Eine im Initialisierer deklarierte Variable existiert nur innerhalb der Schleife. Wenn du danach ihren Endwert brauchst, deklariere sie vor der Schleife: int i; for (i = 0; ...; i++) { }.

Rückwärts zählen und Schrittweiten

Der Iterator kann ein beliebiger Ausdruck sein. Dekrementiere, um rückwärts zu zählen, addiere mehr als eins für größere Schritte oder multipliziere für eine geometrische Folge:

Ausgabe:

3... 2... 1... liftoff
 00 15 30 45
 1 10 100 1000

Achte darauf, dass der Iterator dafür sorgt, dass die Bedingung irgendwann false wird. for (int i = 0; i < 10; i--) zählt von 10 weg und hört erst auf, wenn i nach zwei Milliarden Durchläufen umspringt.

Ein Array per Index durchlaufen

Arrays haben Length, Listen haben Count, und gültige Indizes reichen von 0 bis eins weniger. Der Index gibt dir etwas, das foreach nicht bietet: Zugriff auf die Position, die Nachbarn und das Recht, zurückzuschreiben.

Ausgabe:

#1: 17.99
#2: 4.50
#3: 38.25
#4: 7.43
item 1 vs item 0: down
item 2 vs item 1: up
item 3 vs item 2: down

Die letzte Schleife beginnt bei 1, weil sie jedes Element mit dem vorherigen vergleicht. Die Seite zu Arrays behandelt, wie man Arrays selbst erzeugt, sortiert und kopiert.

Mehrere Schleifenvariablen

Der Initialisierer kann mehrere Variablen desselben Typs deklarieren, und der Iterator kann mehrere aktualisieren, getrennt durch Kommas. Der klassische Einsatz sind zwei Indizes, die aufeinander zulaufen:

Ausgabe:

racecar is a palindrome: True
9, 1, 8, 3

Beide Variablen müssen in einer einzelnen Deklaration denselben Typ haben: int left = 0, right = 10 funktioniert, int i = 0, string s = "" nicht.

Verschachtelte Schleifen

Eine Schleife in einer Schleife durchläuft ihren ganzen Bereich einmal pro Durchlauf der äußeren Schleife. Tabellen und Raster sind der typische Fall:

Ausgabe:

   1   2   3   4
   2   4   6   8
   3   6   9  12
   4   8  12  16

Der innere Rumpf läuft 16 Mal (4 × 4). Verschachtelung vervielfacht die Arbeit schnell: Zwei verschachtelte Schleifen über je 10.000 Elemente ergeben 100 Millionen Durchläufe. Ein break in der inneren Schleife verlässt nur die innere Schleife; die Seite zu break und continue zeigt, wie man beide verlässt.

Endlosschleifen: for(;;)

Alle drei Teile des Kopfs sind optional. Ohne Bedingung läuft die Schleife, bis etwas in ihr sie verlässt:

Ausgabe:

Month 1: 70 left
Month 2: 40 left
Month 3: 10 left
Overdrawn in month 4: -20

for (;;) und while (true) kompilieren zum selben Ergebnis; nimm, was in deiner Codebasis üblich ist.

Off-by-one-Fehler

Der häufigste for-Bug ist eine Bedingung, die einen Schritt zu weit geht:

Ausgabe:

Ada
Grace
Linus
IndexOutOfRangeException at index 3

Ein Array mit 3 Elementen hat die Indizes 0, 1 und 2, i < names.Length ist also die richtige Bedingung. Der spiegelbildliche Bug ist das Rückwärtszählen mit i > 0, das Index 0 nie besucht. Bei einer List<T> wirft derselbe Fehler stattdessen ArgumentOutOfRangeException.

Elemente beim Durchlaufen entfernen

Wer in einer vorwärts laufenden Schleife aus einer List<T> entfernt, verschiebt jedes spätere Element um eine Position nach vorn, die Schleife überspringt also das Element direkt nach jeder Entfernung:

Ausgabe:

forward:  5, 0, 3, 7
backward: 5, 3, 7

Die vorwärts laufende Schleife hat eine 0 übrig gelassen: Nach dem Entfernen von Index 1 ist die zweite Null auf Index 1 gerückt, aber i++ war schon zu Index 2 weitergegangen. Rückwärts zu laufen vermeidet das, weil Entfernungen nur Elemente verschieben, die du schon besucht hast. Als einzeilige Alternative tut stock.RemoveAll(x => x == 0) dasselbe. Eine foreach-Schleife erlaubt das Entfernen überhaupt nicht; sie wirft InvalidOperationException.

Gleitkommazähler

Vermeide double-Schleifenzähler, die auf Gleichheit prüfen. 0.1 hat keine exakte binäre Darstellung, zehnmaliges Addieren ergibt also nicht genau 1.0:

for (double x = 0; x != 1.0; x += 0.1)   // never ends: x skips past 1.0
{
}

Zähle stattdessen mit einer Ganzzahl und berechne den Wert daraus: for (int i = 0; i <= 10; i++) { double x = i / 10.0; }.

for gegenüber foreach

BedarfVerwende
Jedes Element der Reihe nach lesenforeach
Den Index oder die Nachbarn (i - 1, i + 1)for
In ein Array-Element schreibenfor
In Zweierschritten gehen, rückwärts gehenfor
Beim Durchlaufen aus einer List entfernenfor, rückwärts
Eine Collection ohne Indexer (HashSet, Dictionary, LINQ-Ergebnisse)foreach
Etwas N Mal wiederholen, ohne Collectionfor

Bei Arrays kompilieren beide Schleifen zu im Wesentlichen demselben Code, wähle also nach Lesbarkeit, nicht nach Geschwindigkeit.

Häufig gestellte Fragen

Wie lautet die Syntax einer for-Schleife in C#?

for (initializer; condition; iterator) { body }, zum Beispiel for (int i = 0; i < 5; i++) { ... }. Der Initialisierer läuft einmal, die Bedingung wird vor jedem Durchlauf geprüft, und der Iterator läuft nach jedem Durchlauf. Die Schleife endet, sobald die Bedingung zum ersten Mal false ist.

Wie durchlaufe ich in C# eine Schleife rückwärts?

Beginne beim letzten Index und dekrementiere: for (int i = items.Length - 1; i >= 0; i--). Beachte >= 0, nicht > 0, sonst wird das erste Element übersprungen. Rückwärts zu laufen ist auch der sichere Weg, beim Durchlaufen Elemente aus einer List zu entfernen.

Wann sollte ich in C# for statt foreach verwenden?

Nimm for, wenn du den Index brauchst (um Nachbarn zu vergleichen, in ein Array zurückzuschreiben oder in Schritten größer als eins zu gehen), wenn du zählst, statt eine Collection zu durchlaufen, oder wenn du Elemente aus einer Liste entfernst. Nimm foreach, um jedes Element der Reihe nach zu lesen; das ist kürzer und hat keinen Index, bei dem man sich vertun kann.

Wie schreibe ich in C# eine Endlosschleife?

for (;;) { ... } oder while (true) { ... }. Alle drei Teile eines for-Kopfs sind optional, und eine fehlende Bedingung gilt als true. Verlasse die Schleife mit break oder return, sobald deine Abbruchbedingung erfüllt ist.

Warum bekomme ich in meiner for-Schleife eine IndexOutOfRangeException?

Die Bedingung lässt den Index die Länge erreichen: i <= array.Length besucht array[array.Length], eine Position hinter dem letzten Element. Gültige Indizes reichen von 0 bis Length - 1, die Bedingung sollte also i < array.Length lauten (oder i < list.Count bei einer List, die stattdessen ArgumentOutOfRangeException wirft).

Coddy programming languages illustration

Lerne mit Coddy zu programmieren

LOS GEHT'S