Wikipedia · einfach zusammengefasst · Stand
Kontrollstruktur
Kontrollstrukturen sind in der Informatik die Vorgabe, in welcher Reihenfolge die Handlungsschritte eines Algorithmus abgearbeitet werden.
Inhalt6 Abschnitte
Grundidee und Bedeutung
Kontrollstrukturen legen fest, in welcher Reihenfolge die Handlungsschritte eines Algorithmus abgearbeitet werden. In imperativen Programmiersprachen werden sie durch Kontrollanweisungen, auch Steuerkonstrukte oder Kontrollflussanweisungen genannt, umgesetzt. Sie ermöglichen es einem Programm, auf unterschiedliche Zustände und Benutzereingaben zu reagieren: Programmteile können nur unter einer bestimmten Bedingung oder wiederholt ausgeführt werden.
Zu den konventionellen Kontrollstrukturen gehören die Sequenz, die bedingte Anweisung beziehungsweise Verzweigung, die Schleife oder Iteration, die Rekursion und die Blockstruktur. Bei einer Sequenz werden Anweisungen linear und nacheinander ausgeführt. Eine bedingte Anweisung führt Programmteile nur bei einem bestimmten Zustand aus. Eine Schleife wiederholt Anweisungen, solange eine Bedingung gilt oder bis ein bestimmter Zustand erreicht wird. Bei der Rekursion ruft sich eine Prozedur, Funktion oder Methode selbst wieder auf. Eine Blockstruktur gruppiert mehrere Anweisungen und kann dabei den Gültigkeitsbereich von Variablen oder Aktionen beschränken.
Die strukturierte Programmierung beschränkt sich im Kern auf drei Kontrollstrukturen: Sequenz, Verzweigung und Schleife. Dadurch soll unübersichtlicher Quelltext mit häufigem Hin- und Herspringen, sogenannter Spaghetti-Code, vermieden werden. Wiederholungen werden durch Schlüsselwörter klar gekennzeichnet, Bedingungen und Wiederholungen sollen sofort erkennbar sein, und Sprunganweisungen sowie Sprungmarken werden möglichst vermieden.
Entwicklung hin zur strukturierten Programmierung
Kontrollstrukturen wurden auch entwickelt, um Sprünge mit Goto zu vermeiden. Fast jede Programmieraufgabe kann mit Bedingungs- und Wiederholungsstrukturen gelöst werden. Die Programmierung ohne Goto ist in modernen Programmiersprachen heute der Normalfall; Java unterstützt beispielsweise keine Goto-Anweisung mehr.
Heinz Rutishauser entwickelte von 1949 bis 1951 die einfache algebraische Programmiersprache „Superplan“. Sie hatte nur eine Kontrollstruktur: die Für-Schleife. Im Artikel wird dafür die Form „Für i=2(1)n: aᵢ + 3 = aᵢ“ angegeben. Rutishauser kannte Konrad Zuses Arbeiten über Programmiersprachen, darunter den Plankalkül, und wählte „Superplan“ in Anlehnung an Zuses Bezeichnung „Rechenplan“ für ein einzelnes Programm.
In den frühen 1960er Jahren waren Flussdiagramme und Sprunganweisungen üblich. Größere Programme wurden dadurch schnell unüberschaubar und nahezu unwartbar. Edsger W. Dijkstra sprach sich 1968 in seinem Aufsatz „Go To Statement Considered Harmful“ für die Abschaffung des GOTO-Befehls in allen höheren Programmiersprachen aus; der Titel geht allerdings auf Niklaus Wirth zurück.
Im Mai 1966 zeigten Böhm und Jacopini in einem Artikel in „Communications of the ACM“, dass jedes Goto-Programm in ein Goto-freies Programm umgeschrieben werden kann. Dafür genügen eine Verzweigung mit IF THEN ELSE und eine WHILE-Schleife der Form „WHILE Bedingung DO Anweisung“, gegebenenfalls mit etwas Code-Doppelung und booleschen Variablen mit den Werten true und false. Anfang der 1970er Jahre wurde dieser Ansatz durch die Beschränkung auf wenige typische Elemente umgesetzt. Wegweisend war Niklaus Wirths Arbeit mit Pascal.
Sequenz und Bedingungen
Blockstrukturanweisungen kennzeichnen Beginn und Ende einer Blockstruktur beziehungsweise Sequenz. In Pascal oder Visual Basic werden dafür „begin ... end“ verwendet; andere Programmiersprachen benutzen Klammerpaare. Die Anweisungen innerhalb einer Sequenz werden einheitlich eingerückt, damit ihre Zugehörigkeit zum Block sichtbar wird. Python verzichtet auf besondere Blockstrukturanweisungen und kennzeichnet Blöcke allein durch Einrückung.
Eine bedingte Anweisung wird nur ausgeführt, wenn eine bestimmte Bedingung erfüllt ist. Sie besteht aus einer Bedingungsprüfung und der eigentlichen Anweisung, zum Beispiel „IF <Bedingung> THEN <Anweisung>“. Bei positiver Auswertung des Bedingungsausdrucks, also TRUE, wird die Anweisung ausgeführt. Die Verbindung einer Prüfung mit einem Sprungbefehl, etwa „if bedingung then methode()“, ergibt eine Verzweigung, bei der eine Methode nur bei erfüllter Bedingung aufgerufen wird. Durch die Prüfung einer Zählervariable können auf diese Weise auch Schleifen umgesetzt werden.
Verzweigungen und Schleifen
Eine alternative Verzweigung bietet das IF-THEN-ELSE-Konstrukt: „IF <Bedingung> THEN <Anweisung1> ELSE <Anweisung2>“. Ist die Bedingung positiv, wird Anweisung1 ausgeführt. In allen anderen Fällen wird Anweisung2 ausgeführt. So kann ein Programm abhängig von einer Eingabe zwei unterschiedliche Methoden aufrufen. Viele Programmiersprachen erlauben weitere Prüfungen, etwa mit „IF [[ELIF],..] ELSE“, oder verwenden Case- und Switch-Anweisungen.
Im Python-Beispiel ermittelt die Funktion „vorzeichen“ das Vorzeichen des Ausdrucks i. Für i>0 liefert sie „positiv +“, für i<0 „negativ -“ und andernfalls „neutral 0“.
Schleifen führen einen Anweisungsblock wiederholt aus. Der Artikel unterscheidet Zählschleifen, also for-Schleifen, bedingungsgesteuerte Schleifen, also while-Schleifen, mengengesteuerte Schleifen wie for..in beziehungsweise foreach sowie Endlosschleifen. Je nach Programmiersprache gibt es außerdem Anweisungen zum vorzeitigen Verlassen einer Schleife, break, zur Fortsetzung mit der nächsten Iteration, continue, zur Wiederholung der aktuellen Iteration, retry, und zum erneuten Starten der Schleife, redo in Ruby.
Als Python-Beispiel wird „for i in (-5,2,0,1000): print(vorzeichen(i))“ genannt. Dabei wird nacheinander für −5, 2, 0 und 1000 das jeweilige Vorzeichen ausgegeben. List-Comprehensions erzeugen Mengen mithilfe von Schleifen- und Bedingungskonstrukten. Das Beispiel „m = [x**2 for x in range(12) if x%2 == 0]“ ergibt die Quadratzahlen aus geraden x.
Sprünge, Rücksprünge und Ausnahmen
In einer Sequenz werden Anweisungen nacheinander abgearbeitet. Bei einer Sprunganweisung wird dagegen eine durch eine Adresse oder ein Label festgelegte Sprungmarke angesprungen; der Programmablauf wird dort fortgesetzt. Bedingte Sprunganweisungen im Maschinencode bilden meist die Grundlage für bedingte Ausführung und Schleifen in höheren Programmiersprachen. Unbedingte Sprunganweisungen im Maschinencode dienen meist als Grundlage für Funktionsaufrufe oder Endlosschleifen.
Beim Aufruf eines Unterprogramms wird zunächst gespeichert, wohin nach dessen Ende zurückgekehrt werden soll. Gegebenenfalls werden anschließend Aufrufparameter an eine vereinbarte Stelle gelegt, bevor das Unterprogramm angesprungen wird. Wird ein Unterprogramm oder eine andere Methode aufgerufen, kann es beziehungsweise sie mit „return“ verlassen werden. Danach wird das Programm direkt nach dem Absprungpunkt fortgesetzt; dabei können Rückgabewerte übergeben werden.
Sprunganweisungen in höheren Programmiersprachen sind umstritten, weil sie schnell zu Spaghetti-Code führen können. Sie lassen sich dort durch andere Kontrollstrukturen ersetzen. Eine Ausnahmebehandlung übergibt die Kontrolle bei bestimmten Programmzuständen, meistens Fehlerzuständen, an andere Programmebenen zur Weiterbehandlung. Ausnahmen oder Exceptions haben in weiten Teilen die Fehlerbehandlung durch Fehlercodes oder Sprunganweisungen abgelöst.
Darstellung und weitere Einteilungen
Kontrollstrukturen können grafisch visualisiert und modelliert werden. Gebräuchlich sind UML-Sequenzdiagramme als Weiterentwicklung der Struktogramme, auch Nassi-Shneiderman-Diagramme genannt, sowie UML-Aktivitätsdiagramme als Weiterentwicklung der Flussdiagramme, auch Flow Charts genannt. Flussdiagramme beziehen sich auf ISO 5807; spezifischere Programmablaufpläne, kurz PAPs, beziehen sich auf DIN 66001. In Struktogrammen machen besondere Symbole für Verzweigungen und Schleifen die Kontrollstruktur deutlich.
Grafische Darstellungen fördern das Verständnis von Programmabläufen und erleichtern die Fehlersuche. Sie ermöglichen außerdem die Kommunikation mit Personen außerhalb der Softwareentwicklung oder ohne Kenntnisse einer Programmiersprache. Die Abläufe werden dabei intuitiver und fehlerfreier verständlich als in einer lediglich textuellen, aber ebenfalls programmiersprachenunabhängigen Beschreibung in Pseudocode. Struktogramme können anschließend in strukturierten Programmcode umgesetzt werden.
Kontrollflussanweisungen lassen sich nach ihrer Wirkung einteilen: Sie können den Beginn und das Ende eines Blocks kennzeichnen, die Fortsetzung bei einer anderen Anweisung bewirken, ein Programm oder eine Prozedur, Methode beziehungsweise Funktion beenden, Anweisungen nur bei erfüllter Bedingung ausführen, Anweisungsfolgen in einer Schleife nullmal oder mehrmals bis beziehungsweise solange eine Bedingung gilt ausführen oder nach dem Eintritt eines Ereignisses eine Reihe entfernter Anweisungen ausführen. Manche Anweisungen, etwa der unbedingte Sprung, lassen sich nicht eindeutig einer einzelnen Kontrollstruktur zuordnen oder können für mehrere Kontrollstrukturen erforderlich sein. Viele Programmiersprachen, insbesondere imperative Sprachen, enthalten Kontrollanweisungen.