110 likes | 246 Views
Programmieren 1 – Kontrollstrukturen Teil 2. Reiner Nitsch Homepage mit Skript und Materialien zu PG1: www.fbi.h-da.de/~r.nitsch. Hinweise: Die in diesem Kapitel beschriebenen Kontrollstrukturen werden im E-Book auf den
E N D
Programmieren 1 – Kontrollstrukturen Teil 2 Reiner Nitsch Homepage mit Skript und Materialien zu PG1:www.fbi.h-da.de/~r.nitsch Hinweise: Die in diesem Kapitel beschriebenen Kontrollstrukturen werden im E-Book auf den Seiten 73-84 behandelt. ich bitte Sie, dieses Skript und/oder die entsprechenden Seiten im E-Book durchzuarbeiten. Bei der Wiederaufnahme des Vorlesungsbetriebs werden diese Themen nicht mehr behandelt und als bekannt vorausgesetzt. Selbstverständlich bekommen Sie Fragen zu den hier behandelten Themen in der Vorlesung beantwortet.
A A w1 w2 … wn w1 w2 … sonst S1 S2 … Sn S1 S2 … S muss ganzzahliger Ergebnis-Typ sein Kontrollstruktur – Mehrfache Auswahl mit switch – case /73/ In den beiden Diagrammen steht A für einen Ausdruck, der stets einen der (ganzzahligen) Werte w1, w2, . . . ergibt. Der unter dem entsprechenden wi stehende Strukturblock Si wird ausgeführt. Es gibt folgende Variante, bei der der Strukturblock S unter 'sonst' aufgeführt wird, falls A nicht einen der wi ergibt: char Option do { cout << "Moegliche Optionen: a/b/x\n" "Gib Option: "; cin >> Option; switch (Option) { case 'a': S1(); case 'b': S2(); case 'x': cout << "Programmende"; default: cout << "Option gibt es nicht!"; } } while (Option != 'x'); Beispiel: Menüsteuerung C++ kann das nur bedingt: switch ( A ) { case w1: S1; case w2: S2; case wn: Sn; default: S; } break; break; break; break; break verzweigt hinter das Ende der switch-Anweisung break; break; break; Optional; muss nicht letzte Marke sein. optional
In C++ können Zeichen in jedem Ganzzahltyp gespeichert werden, da sie intern als 1-byte-Ganzzahlen dargestellt werden. Liest genau ein Zeichen von Tastatur ein. Notwendig, weil cin Zwischenraumzeichen entfernt. Sentinel ist EOF (iostream) "End of File"; Wert = -1; Eingabe plattformabhängig (Windows: ctrl-Z). EOF muß am Zeilenanfang stehen. sonst wird es von cin ingnoriert und der Eingabepuffer gelöscht Das newline-Zeichen am Ende jeder Eingabe darf nicht mitgezählt werden. Ziffern, Zwischenraum und andere Zeichen zählen void main () { char c; int whitespace(0), number(0), other(0); do { c = cin.get(); switch (c) { case ' ': case '\n': case '\t': whitespace++; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': number++; break; default: other++; break; } } while ( c!= ); --other; cout << "\nDie Eingabe enthielt" << endl << number << " Ziffern" << endl << whitespace << " Zwischenraumzeichen " << "und" << endl << other << " andere Zeichen." << endl; } EOF
Annehmende Schleife /77-79/ – do while Schleife mit nachfolgender Bedingungsprüfung: annehmende Schleife Mit B wird eine Bedingung (logischer Ausdruck) bezeichnet, S ist ein Strukturblock. C++ Syntax: do { //Anweisungen aus S } while (B); B S 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. Unterschied zur annehmenden Schleife: S wird mindestens einmal ausgeführt! Empfehlung: 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; value = 0; do { nextVal = get_int("Gib Ganzzahl>0"); value += nextVal; } while ( nextVal >0 ); return value; } Schleifenvariable Rückgabewert initialisieren Schleifenvariable Richtung Ziel verändern "Nutzleistung" value-=nextVal; sentinel: nextVal<0 Achtung: Sentinelwert wird auch addiert! Was nun?
Annehmende Schleife – do while Beispiel 2 void Counter::countdown() { // PRE: 0<=value if( value==0 )throw std::runtime_error(); do { cout << value << endl; --value; } while (value ); cout << 0 << endl; assert (value == 0 ); } 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: wert = 1 wert > 1 ; z.B wert = 2 > 0 ok ok Frage: Ist das übersetzungsfähig? Compilermeldung: 'c': nichtdeklarierter Bezeichner 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 '}' do { char c; cin >> c; } while ( c != '*' ); char c=''; while ( c != '*' ) { char c; cin>>c; cout<<c; } Diese Schleife endet nie!
Schleife mit fester Wiederholungsanzahl /80-84/ - for Eigentlich überflüssig, aber von Programmierern gern benutzt C++ Syntax SV initialisieren ist äquivalent zu Solange Bedingung B wahr (≠0) ist for ( SVinit; B; SVincrement) S; SVinit while (B) { S SVincrement } S SV verändern Richtung Ziel S Beispiel: Quadratzahltabelle for ( int i = 1; i <= 3; i++ ) cout << i << i*i << endl; Ausgabe • 1 • 4 • 9 1 2 3 4 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
Einfache Beispiele für for - Anweisung a ) Dekrementieren der SV in Schritten von 1 Ausgabe: for ( int i=5 ; i>=1 ; i-- ) { cout << i << ' '; } 5 4 3 2 1 b ) Inkrementieren der SV in Schritten > 1 for ( int i=7 ; i<=35 ; i+=7 ) { cout << i << ' '; } Ausgabe: 7 14 21 28 35 c ) Dekrementieren der SV in Schritten > 1 for ( int i=10 ; i>=2 ; i-=2 ) { cout << i << ' '; } Ausgabe: 10 8 6 4 2
Schleife mit fester Wiederholungsanzahl - for Beispiel: countdown 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 Extremwertenund ggf. Prüfbedingung/Algorithmus korrigieren : value = 1 value > 1 ; z.B value = 2 void Counter::countdown() { if( value<=0 ) throw std::runtime_error(); for ( ; value ; --value ) cout << value << endl; assert (value == 0 ); } >0 cout << 0 << endl; Jeder der 3 Ausdrücke in for-Anweisung kann weggelassen werden: Beispiel for ( ; ; ) cout << "Wird nie fertig" for ( ; true ; ) S besser
Schleife mit fester Wiederholungsanzahl - for Beispiel: GGT zweier Ganzzahlen mit for 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
Der Komma-Operator • meist in for-Anweisung verwendet • erlaubt dort mehrere Ausdrücke, wo syntaktisch nur 1 Ausdruck stehen darf • hat den niedrigsten Vorrang • wertet von links nach rechts aus • Gesamtausdruck hat den Wert des ganz rechts stehenden Ausdrucks Beispiel 1 Was leistet diese Anwendung? int i, j, summe(0); for ( i = 100 , j=1; j < i; i-- , j++ ) summe += i + j; cout << summe; // Addiert (1+100)+(2+99)+…+(50+51) = 5050 // Sinnvolle Anwendung des Kommaoperators // Summe der Zahlen von 1 bis 100 // wird berechnet Beispiel 2 Welche Werte werden zugewiesen? int i,j; int z = ( i=20, j=2*i); // i = 20, j = 40, z = 40 // kein guter Programmierstil! Warum muss hier geklammert werden? Fehler: int j: Neudefinition