FB Informatik Prof. Dr. R.Nitsch C++ - Kontrollstrukturen – Teil 1 Reiner Nitsch ℡ 8417 [email protected] Programmablaufsteuerung FB Informatik Prof. Dr. R.Nitsch • Kontrollstrukturen geben an – in welcher Reihenfolge (Sequenz) – ob (Auswahl) und – wie oft (Wiederholung) Anweisungen ausgeführt werden, bzw. – ob andere Programme aufgerufen werden (Aufruf) • Lineare Kontrollstrukturen – sind Kontrollstrukturen, die nur Sequenz, Wiederholung, Auswahl und Aufruf verwenden, aber keine Sprünge • Strukturierte Programmierung – implementiert einen Algorithmus durch ausschließliche Verwendung einfacher Anweisungen und linearer Kontrollstrukturen Anweisungen Anweisungen einfache einfache Anweisungen Anweisungen lineare Kontrollstrukturen Kontrollstrukturen Sequenz Sequenz Aufruf Aufruf Auswahl Auswahl Wiederholung Wiederholung Zur Erklärung wird eine Beschreibung auf höherer Sprachebene gewählt Struktogramm Struktogramm (DIN (DIN 66261) 66261) Nassi-Shneiderman on the Web 14.05.2008 Kontrollstrukturen - Teil 1 2 Kontrollstrukturen und ihre Struktogramme (DIN 66261) FB Informatik Prof. Dr. R.Nitsch • Struktogramme ermöglichen die visuelle Darstellung von Kontrollstrukturen • Die Grundbausteine von Struktogrammen sind die in den folgenden Abschnitten gezeigten Strukturblöcke. Sie werden jeweils durch ein Rechteck graphisch dargestellt und können durch Schachtelung und Aufeinanderstapeln kombiniert werden. • Der Programmablauf wird stets von oben nach unten gelesen Verarbeitung Anweisung(en) Block Bezeichner Anweisung(en) Sequenz, Folge Anweisung(en) 1 Anweisung(en) 2 … 14.05.2008 Die Verarbeitung ist der einfachste Strukturblock. Er enthält eine oder mehrere Anweisungen in Text- oder Pseudocode-Form. Ein Block (Verbundanweisung) stellt eine Hilfskonstruktion dar, mit der Strukturblöcke zusammengefasst werden können, um ihnen einen gemeinsamen Namen (Bezeichner) zu geben. Man kann einen Block als Funktion im Sinne von C++ auffassen. Der Strukturblock "Sequenz" bzw. "Folge" symbolisiert die Hintereinanderausführung der in ihr auftretenden Strukturblöcke. Eine Sequenz ist selbst eine Verarbeitung Kontrollstrukturen - Teil 1 Counter erzeugen Null setzen um 1 erhöhen C ausgeben void Ausgabe() { Anweisung(en); } Lies Zahl ein Zahl = Zahl2 Gib Zahl aus 3 Abweisende Schleife – while FB Informatik Prof. Dr. R.Nitsch Schleife mit vorausgehender Bedingungsprüfung (pretested loop, abweisende Schleife) Mit B wird eine Bedingung (logischer Ausdruck) bezeichnet, S ist ein Strukturblock. B S Die Abarbeitung beginnt mit einem Test der Bedingung. Ergibt dieser Test false, so wird der nächste Strukturblock verarbeitet. Liefert der Test true, so wird der Strukturblock S ausgeführt. Danach wird der vorliegende Strukturblock erneut ausgeführt (Das heißt, B wird getestet, . . .). C++ Syntax while (B) { //Anweisungen aus S } Beispiel while(true) { /*Anweisung(en)*/ } // unendliche Schleife while(false){ /*Anweisung(en)*/ } //Anweisungen werden nie ausgeführt Schleifenvariable nötig! 14.05.2008 Kontrollstrukturen - Teil 1 4 Abweisende Schleife – while FB Informatik Prof. Dr. R.Nitsch Beispiel Schleifenvariable SV initialisieren solange Ausdruck unter Berücksichtigung von SV true ( ≠ 0) ist "Nutzleistung" Veränderung der SV Richtung Ziel Regeln 1. Zuerst die Zusicherungen. Daraus ergeben sich die notwendigen lokalen Variablen! 2. Algorithmus schreiben und Prüfbedingung festlegen. 3. Prüfen des Algorithmus mit Extremwerten: value = 1; value > 1; class Counter { … int value; void countdown(); public: Counter(int val); … }; Counter::Counter(int val) { value=val; } void Counter::countdown() { assert( ); Vorbedingung? while (value ) Was hier steht, kann erst { nach Definition des Veränderungscout << value << endl; schritts festgelegt werden --value; Nutzleistung } Veränderungsschritt cout << 0 << endl; assert( ); Nachbedingung? } Schleife für Grenzfälle prüfen: value = 1 ? 14.05.2008 Kontrollstrukturen - Teil 1 5 Abweisende Schleife – while - Wait a moment FB Informatik Prof. Dr. R.Nitsch 1. Version long stop (10000); while (--stop); 2. Version: Funktion void wait( double seconds ) Nachteil: Wartezeit von Taktfrequenz des Prozessors abhängig! Abhilfe: Bibliotheksfunktion clock() Headerdateien time.h bzw. ctime enthalten Deklaration. clock() gibt Zeitdauer seit Programmstart zurück Ergebnistyp: clock_t als Aliasname für den tatsächlichen (plattformabhängigen) Ergebnistyp (z.B. long, unsigned long,…) Syntax zur Definition von Aliasnamen: #define clock_t long //Preprozessor ersetzt clock_t durch long im Sourcecode oder besser //wird häufig in Bibliotheken verwendet. typedef long clock_t; #include <ctime> Typ Aliasname void wait(double seconds) { für Typ assert ( seconds >= 0 ); clock_t end = clock() + CLOCKS_PER_SEC * seconds; while ( clock() < end ) ; } 14.05.2008 Kontrollstrukturen - Teil 1 7 Abweisende Schleife – while - Noch ein Beispiel Summe beliebig vieler Zahlen ersten Wert eingeben Ende der Eingabe ? Wert verarbeiten Nächsten Wert eingeben FB Informatik Prof. Dr. R.Nitsch • Frage: Wie entscheidet das Programm, dass alle Zahlen eingegeben sind? • Lösung: Man kann einen speziellen Wert benutzen, um "end of data" zu signalisieren. Ein solcher Wert wird sentinel (dt: Wächter) genannt. int Counter::accumulate() { int nextVal; Schleifenvariable value = 0; Rückgabewert initialisieren cin >> nextVal; sentinel = alle negativen Zahlen while( nextVal >= 0 ) { value += nextVal; cin >> nextVal; Schleifenvariable Richtung Ziel verändern } return value; } 14.05.2008 Kontrollstrukturen - Teil 1 9 HS-Übung 2: abweisende Schleife mit while FB Informatik Prof. Dr. R.Nitsch Finden und korrigieren Sie die Fehler in den nachfolgenden Programmsegmenten a) While ( c <= 5) { product +=c; ++c; b) while (z >= 0) sum += z; c) x=1; while (x <= 10); x++; e) Die Zahlen 1..100 sollen addiert werden! f) n = 1; while ( n < 10 ) cout << n++ << endl; int x=1, total=0; while (x<=100) total +=x; x++; while ( y > 0 ) { cout << y << endl; ++y; } 14.05.2008 Kontrollstrukturen - Teil 1 d) Der nachfolgende Programmcode soll die Werte 1…10 ausgeben! 10 HS-Übung 3: abweisende Schleife mit while FB Informatik Prof. Dr. R.Nitsch Bestimmen Sie die Ausgabe der folgenden Programme : void main( ) { int x = 1, total = 0, y; while ( x <= 5 ) { y = x * x; cout << y << " "; total += y; ++x; } cout << total; } 14.05.2008 void main( ) { int Zeile = 10, Spalte; while ( Zeile >= 1) { Spalte = 1; while ( Spalte <= 10 ) { cout << (Zeile % 2 ? "<" : ">"); ++Spalte; } // while ( Spalte <= 10 ) --Zeile; cout << endl; } // while ( Zeile >= 1) } // main Kontrollstrukturen - Teil 1 11 HS-Übung 4: abweisende Schleife mit while • • • FB Informatik Prof. Dr. R.Nitsch Schreiben Sie eine Funktion ggt die den größten gemeinsamen Teiler zweier Parametern vom Typ int bestimmt und zurück gibt. Testen Sie die Funktion mit einer Anwendung, die solange 2 Zahlen von der Tastatur einliest und den ggt ausgibt, bis eine der beiden Eingabezahlen 0 ist. Hinweis: Um 2 Bedingungen gleichzeitig zu testen, können Sie den logischen && Operator verwenden. Bsp: while ( payIn > 0 && payIn < 100 ) Lösung mit Pseudocode • Vorbedingung? Nachbedingung? • Schleifenvariable ggT mit Minimum beider Zahlen initialisieren • Prüfen, ob beide Zahlen ohne Rest durch ggT teilbar sind • Falls nein, ggT um eins vermindern • Falls ja, Schleife verlassen und mit nächster Anweisung fortfahren 14.05.2008 Kontrollstrukturen - Teil 1 ⇒ Hausaufgabe 12 Annehmende Schleife – do while FB Informatik Prof. Dr. R.Nitsch Schleife mit nachfolgender Bedingungsprüfung: annehmende Schleife S Mit B wird eine Bedingung (logischer Ausdruck) bezeichnet, S ist ein Strukturblock. Zuerst wird S ausgeführt, danach wird B getestet. Ergibt dieser Test false, so wird der nächste Strukturblock verarbeitet. Liefert der Test true, so wird der vorliegende Strukturblock S erneut ausgeführt. B C++ Syntax: do { //Anweisungen aus S } while (B); Unterschied zur annehmenden Schleife: S wird mindestens einmal ausgeführt! Nur anwenden in begründeten Ausnahmefällen, z.B. wiederholte Benutzereingabe Beispiel 1 Vom Benutzer eingegebene positive Zahlen sollen aufsummiert werden. int Counter::accumulate() { int nextVal; Schleifenvariable value = 0; Rückgabewert initialisieren do { cin >> nextVal; Schleifenvariable Richtung Ziel verändern value += nextVal; Implementierung mit abweisender "Nutzleistung" } while ( nextVal >=0 ); oder annehmender Schleife besser? return value; sentinel: nextVal<0 } Achtung: Sentinelwert wird auch addiert! Was nun? 14.05.2008 Kontrollstrukturen - Teil 1 13 Annehmende Schleife – do while Beispiel 2 void Counter::countdown() { assert( value > 0 ); do { cout << value << endl; --value; } while (value ); cout << 0 << endl; assert (value == 0 ); } FB Informatik Prof. Dr. R.Nitsch 1. Wichtig: Zuerst die Zusicherungen. Daraus ergeben sich die notwendigen lokalen Variablen! 2. Algorithmus schreiben und Prüfbedingung festlegen. 3. Prüfen des Algorithmus mit Extremwerten: ok wert = 1 wert > 1 ; z.B wert = 2 ok Frage: Ist das übersetzungsfähig? Compilermeldung: 'c': nichtdeklarierter Bezeichner do { char c; cin >> c; } while ( c != '*' ); Begründung: Speicherklasse von c ist "auto", d.h. c ist lokale Variable im Strukturblock S c ist nur im Strukturblock S definert! Gültigkeitsbereich von c endet mit '}' 14.05.2008 char c = ' '; Diese Schleife while ( c != '*' ){ char c; endet nie! cin >> c; cout << c; Kontrollstrukturen - Teil 1 } 14 Schleife mit fester Wiederholungsanzahl - for FB Informatik Prof. Dr. R.Nitsch Eigentlich überflüssig, aber von Programmierern gern benutzt SV initialisieren Solange Bedingung B wahr (≠0) ist S C++ Syntax ist äquivalent zu for ( SVinit; B; SVincrement) S; SV verändern Richtung Ziel S Beispiel: Quadratzahltabelle for ( int i = 1; i <= 3; i++ ) 1 2 4 cout << i << i*i << endl; 3 SV Initialisierung! C++: Gültigkeitsbereich von i ist nur die for-Anweisung. d.h. for( int i=0; i<10; ++i ) { … } i = 0; quittiert der C++ Compiler mit Fehlermeldung: 'i': nichtdeklarierter Bezeichner 14.05.2008 SVinit while (B) { S SVincrement } Kontrollstrukturen - Teil 1 Ausgabe 1 2 3 1 4 9 15 Einfache Beispiele für for - Anweisung FB Informatik Prof. Dr. R.Nitsch a ) Dekrementieren der SV in Schritten von 1 for ( int i = 5 ; i >= 1 ; i-- ) { cout << i << ' '; } Ausgabe: 5 4 3 2 1 Ausgabe: 7 14 21 28 35 Ausgabe: 10 8 6 4 2 b ) Inkrementieren der SV in Schritten > 1 for ( int i = 7 ; i <= 35 ; i +=7 ) { cout << i << ' '; } c ) Dekrementieren der SV in Schritten > 1 for ( int i = 10 ; i >= 2 ; i -=2 ) { cout << i << ' '; } 14.05.2008 Kontrollstrukturen - Teil 1 16 Schleife mit fester Wiederholungsanzahl - for Beispiel: countdown void Counter::countdown() { assert ( value > 0 ); for ( ; value ; --value ) cout << value << endl; FB Informatik Prof. Dr. R.Nitsch 1. Wichtig: Zuerst die Zusicherungen. Daraus ergeben sich die notwendigen lokalen Variablen! 2. Algorithmus schreiben und Prüfbedingung festlegen. 3. Prüfen des Algorithmus mit Extremwerten und ggf. Prüfbedingung/Algorithmus korrigieren : value = 1 value > 1 ; z.B value = 2 assert (value == 0 ); } Jeder der 3 Ausdrücke in for-Anweisung kann weggelassen werden: Beispiel 14.05.2008 for ( ; ; ) cout << "Wird nie fertig" besser Kontrollstrukturen - Teil 1 for ( ; true ; ) S 17 Schleife mit fester Wiederholungsanzahl - for Beispiel: GGT zweier Ganzzahlen mit for FB Informatik Prof. Dr. R.Nitsch ⇒ Hausaufgabe Lösung mit Pseudocode • Vorbedingung? Nachbedingung? • Schleifenvariable ggT mit Minimum beider Zahlen initialisieren • Prüfen, ob beide Zahlen ohne Rest durch ggT teilbar sind • Falls ja, Schleife verlassen und mit nächster Anweisung fortfahren • Falls nein, ggT um eins vermindern 14.05.2008 Kontrollstrukturen - Teil 1 18 Der Komma-Operator • • • • • FB Informatik Prof. Dr. R.Nitsch meist in for-Anweisung verwendet erlaubt dort mehrere Ausdrücke, wo syntaktisch nur ein Ausdruck stehen darf hat den niedrigsten Vorrang wertet von links nach rechts aus Gesamtausdruck hat den Wert des ganz rechts stehenden Ausdrucks Beispiel 1 int i, j, summe(0); for ( i = 100 , j=1; j < i; i-- , j++ ) summe += i + j; cout << summe; Was leistet diese Anwendung? Beispiel 2 int i,j; int z = ( i=20, j=2*i); Welche Werte werden zugewiesen? Warum muss hier geklammert werden? 14.05.2008 Kontrollstrukturen - Teil 1 19 Verzweigungen (Alternativen): Bedingte Verarbeitung (if) B wahr FB Informatik Prof. Dr. R.Nitsch • Bedingung B entscheidet, ob der Strukturblock S ausgeführt wird falsch S C++ Syntax if ( B ) { // Anweisungen aus S } • Bedingung ist wahr (oder hat Wert != 0) Strukturblock S wird ausgeführt • Bedingung ist falsch (oder hat Wert 0) Strukturblock S wird übersprungen • Ein Strukturblock kann eine einzelne Anweisung sein oder mehrere Anweisungen, die mit {} zu einem Strukturblock zusammengefasst werden. Beispiel if ( zahl cout << if ( zahl cout << 14.05.2008 % 2 == 1 ) "ungerade Zahl"; % 2 == 0 ) "gerade Zahl" oder if (zahl % 2) cout << "ungerade Zahl"; if ( zahl % 2 - 1) cout << "gerade Zahl" Kontrollstrukturen - Teil 1 20 Verzweigung: Einfache Alternative (if…else) B wahr S1 falsch S2 FB Informatik Prof. Dr. R.Nitsch C++ Syntax if ( // } else // } B ) { Anweisungen aus S1 { Anweisungen aus S2 Beispiel if ( zahl%2 == 1 ) cout << "ungerade Zahl"; else cout << "gerade Zahl"; 14.05.2008 Kontrollstrukturen - Teil 1 21 Verzweigung: Verschachtelte if…else Anweisungen B1 wahr B2 w falsch f S2 S1 FB Informatik Prof. Dr. R.Nitsch if ( zahl>0 ) if ( zahl%2 == 0 ) cout << "Positive und gerade Zahl" ; else cout << "Positive und ungerade Zahl" ; gehört immer zum letzten if ! Andere Zugehörigkeit durch Blockbildung: if ( zahl>0 ) { if ( zahl%2 == 0 ) cout << "Positive und gerade Zahl" ; } else cout << "Zahl negativ oder Null" ; B1 wahr B2 w S1 14.05.2008 f falsch Struktogramm dazu ? if (B1) if (B2) S1(); else S2(); else if (B3) S3(); else S4(); syntaktisch ok und übersichtlich durch Einrückungen Struktogramm dazu ? wahr B2 w S2 S1 Kontrollstrukturen - Teil 1 B1 falsch f w S2 S3 B3 f S4 22 Mehrfache Verzweigungen: Mehrfache if…else Anweisungen B1 w f w B2 f w S1 S2 S3 f S4 Jedes else gehört zum vorausgehenden if! 14.05.2008 FB Informatik Prof. Dr. R.Nitsch zuSchnell = radarMessung(); if ( zuSchnell<=10 ) cout << "Glueck gehabt !!" << endl; else if ( zuSchnell<=20 ) bussgeld = 50; else if ( zuSchnell<=30 ) bussgeld = 100; else cout << "Lappen her !!" << endl; zuSchnell = radarMmessung(); if ( zuSchnell<=10 ) cout << "Glueck gehabt !!" << endl; else if ( zuSchnell<=20 ) bussgeld = 50; else if ( zuSchnell<=30 ) bussgeld = 100; else cout << "Lappen her !!" << endl; Kontrollstrukturen - Teil 1 23 HS-Übung 5: Kontrollstrukturen FB Informatik Prof. Dr. R.Nitsch Finden Sie die Fehler in den nachfolgenden Programmsegmenten und korrigieren Sie sie: Lösung For ( x=100 , x>=1 , x++ ) cout << x << endl; Lösung for ( x =.1 ; x!=1.0; x+=.1 ) cout << x << endl; if ( x=2 ) x++ else x--; Lösung if ( age<=40); else if ( age<=50 ) cout << "Grufti"; else; cout << "Uhu"; Lösung 14.05.2008 Kontrollstrukturen - Teil 1 24 HS-Übung 6: Kontrollstrukturen FB Informatik Prof. Dr. R.Nitsch Was wird jeweils ausgegeben? if ( x < 10 ) if ( y > 10) cout << '*'; else cout << '+'; cout << '#'; if (y == 8) if (x == 5) cout << "@" else cout << "#"; cout << "%"; cout << "*"; 14.05.2008 x=8 y=12 x=5 y=8 x=8 y=8 x=8 y=5 ⇒ Hausaufgabe if ( x < 10 ) { if ( y > 10) cout << '*'; } else { cout << '+'; cout << '#'; } x=12 y=8 x=7 y=8 x=8 x=8 y=12 y=8 x=12 x=12 y=8 x=12 x=5 y=7 Kontrollstrukturen - Teil 1 25 HS-Übung 6: Kontrollstrukturen FB Informatik Prof. Dr. R.Nitsch 6.1 Schreiben Sie Programmfragmente, die folgende Ausgaben generieren können: * ** *** **** ***** ***** **** *** ** * ***** **** *** ** * * ** *** **** ***** ⇒ Hausaufgabe Erlaubt sind nur die Ausgabeanweisungen cout << '*', cout << ' ' und cout << endl 6.2 Schreiben Sie ein Programmfragment, das die Zahl π = 4 − 4 4 4 4 + − + − ... + ... 3 5 7 9 mit einer Genauigkeit von 9 Nachkommastellen ausrechnet. 6.3 Schreiben Sie ein Programmfragment, das alle geraden Zahlen 2…100 ausgibt, mit Ausnahme der Zahlen der 10er-Reihe unter Verwendung der while-, do…while und forAnweisung. 14.05.2008 Kontrollstrukturen - Teil 1 26 HS-Übung 7: Kontrollstrukturen • FB Informatik Prof. Dr. R.Nitsch In einer Fabrik zur Produktion von Fahrrad-Zahlenschlössern soll ein Computer eingesetzt werden, der die Schließnummern festlegt. Das nötige Programm soll folgende Anforderungen erfüllen: a) Jede Schließnummer ist eine dreistellige Zahl. b) Paarweise gleiche Ziffern in einer Schließnummer sind nicht erlaubt (z.B. ist 232 keine zulässige Schließnummer) c) Alle gültigen Schließnummern soll das Programm so am Bildschirm ausgeben, dass jeweils 20 Schließnummern in einer Zeile angeordnet sind. d) Es soll die Anzahl der erzeugten, gültigen Schließnummern feststellen und am Bildschirm ausgeben. So sollen Anfang und Ende der Bildschirmausgabe aussehen: 012 013 014 015 016 017 018 019 021 023 024 025 026 027 028 029 031 032 036 037 038 039 041 042 043 045 046 047 048 049 051 052 053 054 056 057 061 062 063 064 065 067 068 069 071 072 073 074 075 076 078 079 081 082 085 086 087 089 091 092 093 094 095 096 097 098 102 103 104 105 106 107 ……………………………………………………………………………………………………………………. 915 916 917 918 920 921 923 924 925 926 927 928 930 931 932 934 935 936 940 941 942 943 945 946 947 948 950 951 952 953 954 956 957 958 960 961 964 965 967 968 970 971 972 973 974 975 976 978 980 981 982 983 984 985 Insgesamt 720 Kombinationen 14.05.2008 Kontrollstrukturen - Teil 1 034 058 083 108 035 059 084 109 937 938 962 963 986 987 27