Version [72090]
Dies ist eine alte Version von ProzProg5Kontrollstrukturen erstellt von NicoleHennemann am 2016-09-27 12:40:00.
Prozedurale Programmierung - Kapitel 5 - Kontrollstrukturen
Inhalte von Dr. E. Nadobnyh
Grundbegriffe
Anweisungen sind Berechnungen (Befehle), die ausgeführt werden, um Daten zu verarbeiten.
Kontrollstrukturen (Steuerstrukturen, Kontrollanweisungen) definieren die Reihenfolge, in der Anweisungen durchgeführt werden. Jede Kontrollstruktur ist selbst eine Anweisung.
Es gibt vier grundlegende Kontrollstrukturen:
1. Sequenz (Folge),
2. Auswahl (Alternative, Verzweigung, Selektion),
3. Schleife (Zyklus, Wiederholung) und
4. Unterprogramm (Aufruf).
Die Mächtigkeit einer Programmiersprache zeigt sich beim Einsatz von Kontrollstrukturen, die in Abhängigkeit von Variablenwerten Abweichungen von linearen Folgen der Anweisungen ermöglichen.
Überblick
Programmablauf
Linearer Ablauf:
Verzweigung:
Wiederholung:
5.1. Sequenzen
1. Eine Sequenz ist eine Reihenfolge von
a) einfachen Anweisungen,
b) Kontrollstrukturen und
c) Blöcken,
welche der Reihe nach abgearbeitet werden.
2. Einfache Anweisung besteht aus:
a) einer Zuweisung, z.B.: a=a+1;
b) einem Aufruf, z.B.: printf(„%d“, a+1); oder
c) einem Ausdruck dem ein Semikolon folgt, z.B.: a++;
Besonderheiten:
a) Eine leere Anweisung besteht nur aus dem Semikolon.
b) Ein Ausdruck ist eine Folge von Operatoren und Operanden, z.B.: a+4;
c) Jede Zuweisung ist in C/C++ ein Ausdruck, z.B.:
a=b=c;
Block
Ein Block ist eine Zusammenfassung von mehreren Anweisungen und Vereinbarungen, die in geschweiften Klammern eingeschlossen sind.
Synonyme: Verbundanweisung, unbenannter Block, Anweisungsblock, zusammengesetzte Anweisungen.
Ein Block ist syntaktisch äquivalent zu einer einfachen Anweisung. Beispiele für Blöcke sind Körper von Funktionen oder Kontrollstrukturen if, else, while, for.
Blöcke sind hierarchisch bzw. baumartig organisiert. Es gibt Sequenzen von Blöcken und geschachtelte Blöcke. Beispiel:
Gültigkeitsbereich
Ein Block kann Namen-Vereinbarungen enthalten, z.B. Variablen-Definitionen. Diese Variablen werden als lokale (auto) Variablen bezeichnet. Ihre Namen gelten nicht im gesamten Programm, sondern nur in bestimmten Gültigkeitsbereichen.
Der Gültigkeitsbereich (scope) eines Namens ist der unmittelbar umgebende Block und alle tiefer geschachtelte Blöcke.
Ein Name kann ab der Stelle der Definition bis zum Ende des Blocks benutzt werden, aber nicht vorher. Variablen werden beim Verlassen des Blocks, in dem sie definiert sind, zerstört. Der Wert geht verloren und kann nicht mehr restauriert werden.
Variablen werden als globale bezeichnet, wenn sie außerhalb eines Blocks definiert sind.
Gültigkeitsbereich. Beispiel
Gültigkeitsbereich von a und g sind beide Blöcke. Gültigkeitsbereich von b ist nur der innere Block.
5.2. Auswahlanweisungen
if ... else-Anweisung
Eine if-Anweisung (Verzweigung, bedingte Anweisung) realisiert die Auswahl zwischen zwei Alternativen.
Syntax (zwei Formen):
Ein Rumpf ist eine Anweisung bzw. ein Block. Der Ausdruck (Bedingung) liefert ein bool-Ergebnis.
Semantik als Struktogramm (Nassi-Shneidermann-Diagramm):
Beispiel:
if (a < b) max = b;
else max = a;
else max = a;
Geschachtelte Alternativen
Beide Rümpfe können ihrerseits neue, untergeordnete Alternativen sein, d.h. mehrere if-else-Anweisungen können geschachtelt werden.
Beispiel: Berechnung des Vorzeichens einer Zahl x. Ergebnis sign soll +1 für positive Zahlen, -1 für negative Zahlen und 0 für Null erhalten.
Folgende Varianten sind äquivalent:
if(x > 0) sign = 1; if(x < 0) sign = -1; if(x == 0) sign = 0; |
if(x > 0) sign = 1; else if(x < 0) sign = -1; else sign = 0; |
Mehrdeutigkeit: zu welchem if gehört das else?
if(x > 0) if(x
Eine switch-Anweisung (Verteiler) realisiert die Auswahl zwischen mehreren Alternativen.
Syntax:
1) Ein Rumpf ist eine Anweisung bzw. ein Block.
2) Der Ausdruck muss ganzzahlig sein.
3) k1 bis kN sind Literale.
Semantik als Struktogramm:
switch-Ablauf
1. Der Ausdruck in switch wird ausgewertet.
2. Der Ausdruckswert wird mit allen Literalen verglichen.
3. Falls passendes Literal gefunden wird, wird entsprechender Rumpf ausgeführt.
4. Ansonsten wird default-Rumpf ausgeführt.
5. break verlässt die switch-Konstruktion.
Beispiel. Wochentag als Nummer :
int tag; cin >> tag;
switch (tag)
{ case 6: cout << "Samstag"; break;
...
case 5: cout << "Freitag"; break;
default: cout<< "FEHLER";
}
switch (tag)
{ case 6: cout << "Samstag"; break;
...
case 5: cout << "Freitag"; break;
default: cout<< "FEHLER";
}
⇒ Demo 2. switch
switch-Besonderheiten
1) Die switch–Anweisung ist eine Verallgemeinerung der bedingten Anweisung
2) Die Anordnungsreihenfolge ist beliebig.
3) default-Anweisung ist optional. Wenn default fehlt, wird keine Anweisung ausgeführt.
4) Gleiche Literale sind unzulässig. Compiler prüft und erkennt Duplikate.
5) Eine echte Mehrfachauswahl wird durch die switch-Anweisung erst zusammen mit der break-Anweisung realisiert.
6) break sind optional. Ohne break werden auch andere Rümpfe ausgeführt, welche nach dem ausgewählten Rumpf folgen.
switch-Anweisung mit und ohne break
Mehrfache Literale
Eine Alternative kann mit mehreren Literalen begonnen werden. Das ist dann nützlich, wenn bei unterschiedlichen Werten die gleiche Alternative betreten werden soll.
Beispiel:
char c;
...
switch (c)
{ case ’a’: case ’e’: case ’i’: case ’o’: case ’u’:
case ’A’: case ’E’: case ’I’: case ’O’: case ’U’:
cout << "c ist ein Vokal" << endl;
break;
default: cout << "c ist kein Vokal" << endl;
}
...
switch (c)
{ case ’a’: case ’e’: case ’i’: case ’o’: case ’u’:
case ’A’: case ’E’: case ’I’: case ’O’: case ’U’:
cout << "c ist ein Vokal" << endl;
break;
default: cout << "c ist kein Vokal" << endl;
}
5.3. Schleifen
for-Schleife
for-Schleife ist eine kopfgesteuerte Schleife (Zählschleife) mit freier Wahl der Schrittweite.
Syntax:
Ein Rumpf ist eine Anweisung bzw. ein Block.
Semantik als Struktogramm:
Beispiel:
double x = exp(1);
for(int i = 1; i < 20; i++)
{
cout << setprecision(i) << x << endl;
}
for(int i = 1; i < 20; i++)
{
cout << setprecision(i) << x << endl;
}
for –Schleife in Details
1. Als Ergebnis des Bedingungsausdruckes (Ausdruck2) wird ein bool-Wert erwartet. Der Bedingungsausdruck wird bei jeder Wiederholung neu ausgewertet.
2. Die for-Schleife wird zum Durchzählen einer Laufvariable (Zählvariable, Schleifenzähler) mit bekannter Anzahl von Schleifendurchläufen empfohlen.
3. Alle drei Ausdrücke im Kopf der Schleife sind optional, nicht aber die trennenden Semikolons.
Beispiel der Endlosschleife: for( ; ; ) ;
4. Die Laufvariable wird oft im Ausdruck1 definiert und gilt dann lokal innerhalb der Schleife jedoch nicht mehr nach der Schleife.
5. Der Rumpf kann mehrmals oder niemals ausgeführt werden.
Komma-Operator
Der Komma-Operator (Auflistungs-Operator) erlaubt die Verwendung von mehreren Ausdrücken an Stellen, an denen nur ein Ausdruck stehen darf. Hauptsächlich wird er im ersten und letzten Ausdruck des Steuerkopfes der for-Anweisung verwendet.
Der Mißbrauch des Komma-Operators zeigt den schlechten Programmierstil, z.B.:
for(int i=1; i<20; cout<<setprecision(i)<<x<<endl, i++);
Der Wert des durch den Komma-Operator gebildeten Gesamtausdrucks ist gleich dem Wert des rechten Teil-Ausdrucks.
Fehlerhaftes Beispiel:
for(float x=-1; x<1; x+=0,5) cout << x << endl;
while-Schleife
Kopfgesteuerte Schleife.
Syntax:
Ein Rumpf ist eine Anweisung bzw. ein Block.
Semantik mit dem Struktogramm:
Der Rumpf kann mehrmals oder niemals ausgeführt werden.
Beispiel:
int summe = 0;
int zahl = 1;
while (zahl <= 100)
{ summe += zahl;
zahl++;
}
int zahl = 1;
while (zahl <= 100)
{ summe += zahl;
zahl++;
}
do ... while-Schleife
Fußgesteuerte Schleife
Syntax:
Ein Rumpf ist eine Anweisung bzw. ein Block.
Semantik mit dem Struktogramm:
Der Rumpf wird in jedem Fall wenigstens einmal ausgeführt.
int summe = 0; int zahl = 1;
do
{ summe += zahl;
zahl++;
}
while (zahl <= 100);
do
{ summe += zahl;
zahl++;
}
while (zahl <= 100);
Geschachtelte Schleifen
Ein Rumpf einer Schleife ist selbst eine beliebige Anweisung, z.B. untergeordnete, innere Schleife. Übergeordnete Schleife wird als äußere Schleife bezeichnet. Schleifen können beliebig tief geschachtelt werden.
Beispiel. Das folgende Programm erzeugt eine Multiplikationstabelle:
for(int i=1; i<=10; i++) { cout<<setw(2)<<i<<" |"; for(int j=1; j<=10; j++) { cout<<" "<<setw(3)<<i*j; } cout<<endl; }
⇒ Demo 4. geschachtelt
Verwendung von Schleifen
Alle Schleifensarten sind gleichwertig: jede könnte durch eine andere ersetzt werden. Sinnvoll ist allerdings eine differenzierte Auswahl:
1. Verwendung der while-Schleife, wenn die Anzahl der Iterationen unbekannt ist und auch Null Durchläufe möglich sind.
2. Verwendung der do...while-Schleife, wenn die Anzahl der Iterationen unbekannt ist und mindestens ein Durchlauf nötig ist.
3. Bevorzugung der for-Schleife insbesondere dann, wenn die Anzahl der Iterationen bekannt ist.
Besondere Aufmerksamkeit ist bei Verwendung der do...while -Schleife geboten. Empirische Untersuchungen haben gezeigt, dass bei der Verwendung der do-Schleife etwa 50% mehr Fehler auftreten als bei Verwendung der while-Schleife.
Die break-Anweisung
kann in allen Schleifen verwendet werden, um die aktuelle Iteration vorzeitig zu beenden.
Beispiel:
while (true)
{ . . .
if ( . . . ) break;
. . .
}
{ . . .
if ( . . . ) break;
. . .
}
kann auch in switch-Anweisungen verwendet werden.
Die continue-Anweisung
führt einen Sprung zum Rumpf-Ende aus, um dann mit dem nächsten Schleifendurchlauf fortzufahren.
Beispiel. Die folgenden Varianten sind äquivalent:
5.4. Empfehlungen zum Programmieren
Ziel der Empfehlungen
Ein syntaktisch und semantisch korrektes Programm kann Logikfehler enthalten und deswegen die nicht erwarteten Ergebnisse liefern.
Wir können Fehler in unseren Denkansätzen erkennen und versteckte Programmfehler teilweise vermeiden, wenn bei der Programmierung einige Empfehlungen eingehalten werden:
- Lesbarkeit von Programmen,
- Benutzerfreundliche Dialoge,
- Schrittweise Verfeinerung,
- Integrierte Dokumentation,
- Verwendung der problemadäquaten Datentypen,
- Fehlerüberprüfung.
Lesbarkeit von Programmen
Einige Empfehlungen und Forderungen werden in der strukturierten Programmierung entwickelt:
1) Programme werden für Menschen geschrieben. Programme sollen so dargestellt werden, dass ihr Ablauf einfach zu erfassen und zu verändern ist.
2) Die Verwendung von expliziten Sprüngen „goto“ soll prinzipiell vermieden werden.
3) Alle Algorithmen lassen sich prinzipiell aus drei folgenden Konstrukten aufbauen:
a) Sequenz,
b) if-else-Auswahl und
c) while- Schleife.
4) Programme sollen grundsätzlich kommentiert werden.
5) Es ist schwierig, aber auch wichtig treffende, sinnvolle Namen für Funktionen, Variablen u.a. zu finden.
6) Besonders wichtig für die Lesbarkeit ist die saubere Formatierung des Programms bzw. Einrücken von Befehlsfolgen.
7) Die Vernachlässigung von diesen Empfehlungen kann fatale Folge haben, z.B.:
a) "Spaghetti-Codes„ sind kaum wartbar;
b) Unstrukturierte Programme sind nach kurzer Zeit
unleserlich selbst für den Autor.
⇒ Demo 5. Strukturierung
Benutzerfreundliche Dialoge
Bei der Ausführung muss ein erklärender Text auf dem Bildschirm erscheinen:
1. In der Aufforderung zu einer Eingabe muss die Art der einzugebenden Daten und das erwartete Format beschrieben werden.
2. Bei der Ausgabe muss erklärt werden, welche Daten hier ausgegeben werden.
3. Der Benutzer soll über auftretende Fehler (unkorrekte Eingabe, fehlende Dateien usw. ) informiert werden und zu den möglichen Aktivitäten aufgefordert werden.
CategoryDelete