Read this article in English

Programmier-Terminologie: Kontrollstruktur(en)

Was ist eine Kontrollstruktur und wie kann sie in selbst geschriebenen Programmen genutzt werden? Diese Fragen sollen hier geklärt werden.

Kontrollstrukturen sind spezifische Kommandos innerhalb von (imperativen) Programmiersprachen, mit denen der logische Fluss des Programms während seiner Ausführung gesteuert werden kann. Dabei bestimmen die Kommandos im Zusammenspiel mit zu bewertenden bzw. zu berechenden Ausdrücken, welcher Teil des Programms als nächstes ausgeführt wird.

Es gibt zwei wesentliche Arten von Kontrollstrukturen:

Beide Arten von Kontrollstrukturen helfen dabei, die Programmlogik klarer zu gestalten und auf klassische Sprungkommandos wie das "GOTO" in früheren Programmiersprachen zu vermeiden. Durch die Verwendung solcher Sprungkommandos wurde die Fehlersuche meist sehr schwierig, da die Logik des Programms nicht leicht zu durchschauen war.

Verzweigungs-Kontrollstrukturen

Bei Verzweigungs-Kontrollstrukturen wird Programmcode, der sich in einem der untergeordneten "Zweige" der Kontrollstruktur befindet, entweder ausgeführt oder übersprungen, je nachdem, was sich bei der Berechnung des Wertes einer angegebenen Bedingung in Abhängigkeit von den aktuellen Werten der verwendeten Variablen ergibt.

Die beiden üblichen Typen von Verzweigungs-Kontrollstrukturen sind folgende:

if-then-else Verzweigungen

Bei "if-then-else" Kontrollstrukturen (so benannt nach den üblicherweise verwendeten Englischen Kommandoworten) wird der folgende Programmcode in zwei Teile aufgeteilt. Dabei kann der "else"-Teil des Codes auch leer sein, falls nur ein einzelner Block in Abhängigkeit von aktuellen Werten ausgeführt oder übersprungen werden soll.

Die zu prüfende Bedingung für die Entscheidung, welcher Teil des Codes ausgeführt werden soll, folgt überlicherweise auf das "if" Kommandowort. Dabei wird die Bedingung bei dieser Art von Kontrollstruktur nur einmal, direkt zu Beginn der Kontrollstruktur geprüft.

Die Syntax der "if-then-else" Kontrollstrukturen unterscheidet sich bei verschiedenen Programmiersprachen leicht in den Details, die Funktionsweise und Struktur ist jedoch überall gleich:

  1. "IF"-Kommando: Im Rahmen der Ausführung des anfänglichen "IF"-Kommandos am Anfang der Kontrollstruktur wird die hier angegebene Bedingung vom Computer geprüft, indem der angegebene Ausdruck berechnet wird. Aufgrund des berechneten Wertes ergibt sich dann für die zu prüfende Bedingung ein boolescher Wert (wahr oder falsch). Falls die Bedingung wahr ist ("true"), dann werden die folgenden Programmzeilen ausgeführt bis hin zum Beginn des "ELSE"-Zweiges oder einem "END"-Kommando, ansonsten werden sie übersprungen.
  2. "ELSE"-Zweig: In den meisten Programmiersprachen ist der "ELSE"-Zweig zu einem "IF"-Kommando optional. Falls der "ELSE"-Zweig verwendet wird und gültige Code-Zeilen enthält, dann werden diese Zeilen bis hin zum "END"-Kommando ausgeführt, falls die zuvor beim "IF"-Kommando durchgeführte Bedingungsprüfung den Wert "falsch" ("false") ergeben hat. Ansonsten werden die im "ELSE"-Teil enthaltenen Codezeilen übersprungen.
  3. "END"-Kommando: Die "IF"-Kontrollstruktur wird in den meisten aktuellen Programmiersprachen mit einem "END"-Kommando hinter der letzten relevanten Codezeile abgeschlossen. Einige Sprachen verwenden anstelle eines Kommandowortes hier auch spezielle abschließende Sonderzeichen wie z.B. schließende geschweifte Klammern ("}"). Nach diesem Abschluss der Kontrollstruktur wird dann das weitere Programm zeilenweise ausgeführt (bis hin zur nächsten Kontrollstruktur).

Da solche "if-then-else" Strukturen in den meisten Programmiersprachen auch innerhalb des "if"- oder "else"-Zweiges einer anderen "if-then-else" Kontrollstruktur verwendet werden können, lassen sich damit recht komplexe logische Strukturen innerhalb eines Programms erzeugen. Da aber an jedem Punkt, an dem eine Bedingung geprüft wird, immer nur eine einfache binäre "wahr"/"falsch"-Struktur vorhanden ist, lässt sich der logische Fluss des Programms trotzdem recht einfach nachvollziehen.

Das folgende kurze Beispiel zeigt eine "if"-Kontrollstruktur in der Programmiersprache C:

 CODE: Select all lines of code for copying

if (x < 20)
  CalculateY();
else
  CalculateZ();


In diesem Beispiel wird die Funktion "CalculateY" ausgeführt, falls der aktuelle Werte der Variablen "X" kleiner als 20 ist. Falls "X" größer oder gleich 20 ist, wird stattdessen die Funktion "CalculateZ" aufgerufen.

case Verzweigungen

Bei "case"-Kontrollstrukturen werden genau wie bei den "if"-Kontrollstrukturen angegebene Bedingungen geprüft, um zu entscheiden, welcher Teil des Programms als nächstes ausgeführt werden soll. Die beiden Arten von Kontrollstrukturen unterscheiden sich jedoch darin, wann und wo der boolesche Wert der jeweiligen Bedingung berechnet wird, sowie in der Anzahl der Prüfungen.

Bei "case"-Strukturen kann nicht nur eine einzelne Bedingung geprüft werden, sondern verschiedene Bedingungen, die sich auf die gleiche Variable beziehen.

Die übliche Syntax für "case"-Kontrollstrukturen sieht in den meisten Programmiersprachen in etwa so aus:


CASE (Variable oder Berechnung)
  WHEN wert_1:
    kommando 1
    kommando 2
    ...
  WHEN wert_2:
    kommando 3
    ...
  WHEN OTHERS:
    ...
ENDCASE


Die Variable oder Berechnung nach dem initialen "CASE"-Kommandowort liefert zur Laufzeit des Programms einen Wert, der dann in den Bedingungsprüfungen innerhalb der Kommandostruktur verwendet wird. Dieser Wert kann numerisch, boolesch, ein einzelnes Zeichen oder eine Zeichenkette (string) sein.

Innerhalb der Kommandostruktur werden meist spezifische Einzelwerte in den Bedingungsprüfungen verwendet, die mögliche Werte oder Wertintervalle für die verwendete Variable oder Berechtnung darstellen. Ist der aktuelle Wert der Variablen (oder Berechtnung) gleich dem jeweiligen Referenzwert der Bedingungsprüfung, so ist der Wert der Bedingung "wahr" und die Codezeilen des jeweiligen "WHEN"-Blocks werden ausgeführt. Ansonsten werden die zugehörigen Programmzeilen übersprungen und die nächste Bedingung wird geprüft, bis das Ende des "CASE"-Blocks erreicht ist.

Hier ist ein kurzes Beispiel für eine case-Kontrollstruktur in der Programmiersprache C:

 CODE: Select all lines of code for copying

switch (cval) {
   case 0: v = 1; break; 
   case 1: v = 2; break; 
   case 2: v = 5; break;
   default: v = 10;      
}

In diesem Beispiel wird der Wert der Variablen "v" auf 1, 2, 5 oder 10 gesetzt, je nachdem, welchen Wert die Variable "cval" hat. Falls "cval" einen anderen Wert als 0, 1 oder 2 hat, wird der Variablen "v" jeweils der Wert 10 zugewiesen.


Schleifen-Kontrollstrukturen

Im Gegensatz zu den oben beschiebenen Varianten von Verzweigungs-Kontrollstrukturen wird der Programmcode innerhalb einer Schleife im Regelfall ein- oder mehrfach nacheinander ausgeführt. Ein Überspringen des Codes innerhalb einer Schleife erfolgt nur, falls die zugehörige Bedingung direkt zu Beginn der Schleife geprüft wird und der so ermittelte boolesche Wert "falsch" ist.

Bei den meisten Programmiersprachen gibt es drei verschiedene Varianten von Schleifen-Kontrollstrukturen:

In vielen Programmiersprachen gibt es spezielle Schleifen-Exit-Kommandos, mit denen eine Schleife bei der Ausführung des Programms vorzeitig verlassen werden kann, wenn eine bestimmte Bedingung erfüllt ist. Allerdings wird im Regelfall soweit wie möglich auf die Verwendung solcher Exit-Kommandos verzichtet, da das Programm sich im Fehlerfall sonst schwerer zu analysieren ist.

For-Schleifen

"for"-Schleifen oder Zählschleifen verwenden eine Zähler-Variable und eine zugehörige Bedingungsprüfung um zu bestimmen, wie oft der Programmcode innerhalb der Schleife ausgeführt werden soll.

Die Zähler-Variable ist meistens eine integer-Variable für ganzzahlige Werte, die um eins herauf- oder heruntergezählt wird, bis die Endbedingung für die Schleife erfüllt ist.

Hier ist ein Beispiel einer "for"-Schleife in der Programmiersprache BASIC:

 CODE: Select all lines of code for copying

FOR i=2 TO 18 STEP 2
  ' tue irgendwas
  ' tue noch mehr
  ' ...
NEXT i

Im obigen Beispiel ist die Variable "i" ein Integer-Wert, der bei jedem Durchlaufen der Schleife um jeweils zwei erhöht wird, beginnend mit einem Wert von 2, bis zum maximalen Wert von 18. Ohne die zusätzliche Angabe des Kommandowortes "STEP" mit dem darauf folgenden Wert 2 würde der Wert von "i" jeweils nur um 1 erhöht werden, so aber werden jeweils 2 dazu addiert. Die Variable "i" nimmt also die Werte 2, 4, 6, 8 usw. bis 18 an.

Alle Code-Zeilen innerhalb der Schleife werden wieder und wieder ausgeführt, bis der angegebene maximale Wert des Zählers erreicht ist. Danach geht es mit der Ausführung des Programmcodes weiter, der nach dem Ende der Schleifenkontrollstruktur beginnt.

Bei einigen Programmiersprachen wie C, C++ oder Java kann die Ausstiegsbedingung für das Verlassen der Schleife auch komplexer sein. Trotzdem ist der Mechanismus auch in diesem Fall der gleiche wie oben beschrieben: der Code innerhalb der Schleife wird solange immer wieder ausgeführt, bis die Prüfung der Bedingung nicht mehr den Wert "wahr", sondern den Wert "falsch" ergibt.

In manchen Programmiersprachen gibt es außerdem noch eine weitere Variante der "for"-Schleife: die "foreach"-Schleife. Anstelle eines einfachen Zählers, mit dem die Wiederholungen der Schleife gezählt werden, wird bei einer "foreach"-Schleife eine beliebige, zuvor definierte Menge mit gleichartigen Elementen genutzt, die nacheinander durchlaufen werden. Dabei können diese Elemente nicht nur Zahlen sein, sondern auch einzelne Zeichen, Zeichenketten oder komplette Datensätze, die ihrerseits aus jeweils mehreren Werten zusammengesetzt sind. Der "Zähler" der Schleife nimmt in diesem Fall nacheinander jeden der definieren Einzelwerte an, und die Schleife wird beendet, sobald das letzte Element der Menge abgearbeitet wurde.

Hier ist ein Beispiel aus der Programmiersprache "Perl":

 CODE: Select all lines of code for copying

foreach $name ("Anne", "Tom", "Peter") {
  print("Hello, $name.\n");
}

In diesem Beispiel fungiert die Zeichenketten-Variable (String-Variable) "$name" als Schleifenzähler. Dieser Variable werden beim Durchlaufen der Schleife nacheinander alle Werte der angegebenen Menge von Zeichenketten (die Namen von "Anne" bis "Peter") einzeln zugewiesen. In jedem Schleifendurchlauf wird dann der aktuelle Name mit einem kurzen Gruß ausgegeben. Dies geschieht so lange, bis der letzte Name der Liste erreicht wurde und die Schleife damit durchlaufen wurde.

While-Schleifen

Ähnlich wie bei "for"-Schleifen wird der Programmcode innerhalb von "while"-Schleifen immer wieder ausgeführt, bis die geprüfte Bedingung für das Durchlaufen der Schleife nicht mehr wahr, sondern falsch ist.

Im Vergleich zu "for"-Schleifen benötigen "while"-Schleifen keinen ganzzahligen Zähler. Die Schleifenbedingung kann eine Prüfung sein, die aus einer beliebigen Formel zusammengesetzt aus Variablen, Funktions-Rückgabewerten oder ähnlichem bestehen kann. Wichtig ist dabei nur, dass innerhalb der Schleife unter bestimmten Umständen eine Änderung der für die Schleifenbedingung relevanten Faktoren geschehen kann, so dass die Schleife auch wieder verlassen werden kann.

Hier ist ein kurzes Beispiel in einer klassischen Variante der Programmiersprache "BASIC":

 CODE: Select all lines of code for copying

X = 2
WHILE ( X*X < 100 )
  PRINT X, X*X
  X = X + 3
WEND

Bei diesem Beispiel wird der Variablen "X" vor dem Beginn der Schleife der Wert 2 zugewiesen. Bei jedem Schleifendurchlauf wird der aktuelle Wert von X zusammen mit dem Wert von X mal X ausgegeben und anschließend der Wert von X um jeweils 3 erhöht. Die Schleife wird verlassen, sobald der Wert von X mal X größer oder gleich 100 ist.

Repeat-Schleifen / Do-Schleifen

"repeat"-Schleifen oder "do"- bzw. "do-while"-Schleifen funktionieren wie "while"-Schleifen. Der Unterschied liegt jedoch darin, dass die Schleifenbedingung erst am Ende der Schleife geprüft wird, und nicht bereits zu Beginn der Schleife. Daher wird der Code innerhalb von "repeat"- bzw. "do"-Schleifen mindestens einmal durchlaufen, während er bei "while"-Schleifen ggf. auch komplett übersprungen werden kann, falls die Schleifenbedingung direkt zu Beginn falsch ist.

Das folgende Beispiel entspricht dem vorherigen Beispiels einer "while"-Schleife. Es ist gewissermaßen die "repeat"-Schleifen-Variante davon:

 CODE: Select all lines of code for copying

X = 2
REPEAT
  PRINT X, X*X
  X = X + 3
UNTIL ( X*X < 100 )

Auf den ersten Blick unterscheidet sich die "repeat"-Schleife kaum von der "while"-Schleife. Auch in diesem Fall werden die Codezeilen innerhalb der Schleife so lange wiederholt, bis der Wert von X mal X größer oder gleich 100 ist.

Einen Unterschied gibt es allerdings: vor der ersten Prüfung der Schleifenbedingung "X*X y 100" wird X bereits einmal um 3 erhöht. Bei der "while"-Schleife erfolgt diese Änderung des Wertes von X erst nach der Prüfung der Schleifenbedingung. Dies führt dazu, dass bei der "repeat"-Schleife das Verlassen der Schleife etwas eher erfolgt.

In den hier verwendeten Beispielen führt die gleiche Schleifenbedingung zu einer Schleife mit dem gleichen Verhalten. Die Zahl der Schleifendurchläufe ist jedoch unterschiedlich.

Alles unter Kontrolle

Kontrollstrukturen sind ein wesentlicher Bestandteil der meisten Programme. Im Zusammenspiel mit Funktionen, Objekten, Variablen usw. sind sie essentiell für die Gestaltung der Logik eines Programms.

Durch die Verwendung verschiedener Kontrollstrukturen kann sich das Programm intelligent und flexibel verhalten, so dass der Computer während der Ausführung des Programms verschiedenste Entscheidungen in Abhängigkeit von den aktuellen Gegebenheiten treffen kann.