Gliederung Programmiersprachen 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. Programmiersprachen Einführung in C Teil 5: Kontrollstrukturen Prof. Dr. Jörg Schwenk Lehrstuhl für Netz- und Datensicherheit Von der Maschinensprache zu C Die Struktur von C-Programmen Variable und Datentypen in C Bildschirm Ein-/Ausgabe Kontrollstrukturen Funktionen Programmierstil, Programmierrichtlinien Felder u. Zeichenketten Ausdrücke Arbeiten mit Dateien Strukturen, Aufzählungstypen Zeiger Enums, Strukturen und Unions Speicherklassen Optional: Vertiefung einiger Themen Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg Kontrollstrukturen Verzweigung mit IF 1 Ohne Kontrollstrukturen: 1 lineare Programme 1 sequentielle Ausführung der Anweisungen 1 allgemeine Formen bedingter Anweisungen if ( <Bedingungsausdruck> <Anweisung> ; if 1 Probleme: 1 keine Reaktion auf äußere und innere Bedingungen möglich 1 keine Ausnahmebehandlung / Fehlerbehandlung möglich 1 starrer Ablauf, keine Wiederholungen 1 Parametrisierung eingeschränkt 1 arme Algorithmen-Schemata für Programmentwurf ) // Einzelanweisung ( <Bedingungsausdruck> ) // Einzelanweisung <Anweisung> ; else <Anweisung> ; 1 2 // Einzelanweisung Behandlung von Anweisungsfolgen if ( <Bedingungsausdruck> ) <Anweisungsfolge> { // Anweisungsfolge in { ... } } 1 Abhilfe 1 Anweisungen für die bedingte Ausführung von Anweisungsblöcken 1 Verzweigung und Mehrfachverzweigung, Kaskadierung von Bedingungen 1 Wiederholungsanweisungen für die wiederholte Ausführung von Anweisungsblöcken if ( <Bedingungsausdruck> ) <Anweisungsfolge> { // Anweisungsfolge in { ... } } else { <Anweisungsfolge> // Anweisungsfolge in { ... } } Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 3 Beispiele für Fallunterscheidungen Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 4 Beispiel: Zahlenklassifizieren 1 Schleichwegfahrt: Fahrt Richtung Osten, wenn Tageszeit zwischen 7 und 19 Uhr und Fußgängerampel auf rot, dann fahre Schleichweg, sonst fahre geradeaus. void main () { const int zehn = 10; int wert = 0; printf(”\ngib eine Zahl ein : ”); scanf("%d", &wert); ( wert == zehn ){ // falls Wert gleich (Vorsicht !!) printf(”der Wert ist zehn ”); } else { // andernfalls überprüfe, ob if ( wert > zehn ){ printf(” Der Wert ist größer als zehn ”); } else { // falls das auch nicht gilt printf("Der Wert ist kleiner als zehn ”); } } if 1 Abbruchbedingungen für Eingaben: noch eine Diskette formatieren ? 1 Entscheidungen über Variablenwerte 1 Steuerung technischer Vorgänge: Wenn Vorlauftemperatur unter Soll, dann öffne Mischer 1 wenn Vorlauftemperatur nicht höher als (Zimmer-Temp. + 5°) und Rücklauf zwischen Vorlauf und (Vorlauf - 2°), dann Umwälzp umpe aus Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg } 5 Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 6 1 Beobachtungen (bei großer Schachtelungstiefe) Vergleiche und logische Operatoren 1 Vergleichsoperatoren und logische Operatoren liefern als Ergebnis ... 1 in C++ Wahrheitswerte (Datentyp: bool), 1 in C jedoch einfach einen Zahlenwert, welcher entsprechend interpretiert wird wahr / falsch true / false ≠0 / 0 (interne Realisierung) 1 Große Schachtelung führt schnell zur Unübersichtlichkeit 1 Einrückung im Programmtext ermöglicht Überblick 1 Strukturierung durch Verteilen auf mehrere Funktionen fördert Übersichtlichkeit 1 Falls möglich auf switch-Anweisung (später) ausweichen 1 Achtung beim Test: im Extremfall Verdoppelung der Programmpfade mit jeder neuen Entscheidungsebene 123456789 7 (Schachtelungsebene) 44897777 477712342356789 566 Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 7 1 Vergleichsoperatoren 1 gleich | ungleich|kleiner |größer |kleiner oder gleich |größer oder gleich == != < > <= >= 1 Vergleiche haben geringere Auswertepriorität als arithmetische Operatoren if (i < lim-1) --> if (i < (lim-1)) // wie erwartet! Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 8 Vergleiche und logische Operatoren Verwendung von Bedingungen 1 Besonderheit in C/C++ 1 Jeder Ausdruck kann als Wahrheitswert interpretiert werden 1 Daher: if (3*x/12) zulässig; In Abhängigkeit von x wird verzweigt 1 Insbesondere:if ( x = 12 ) ebenfalls zulässig; Konsequenzen??? 1 Wertzuweisung hat niedrigere Priorität als Vergleichsoperatoren! if ( (c=getchar()) != 'n') // Klammerung nötig! 1 Beispiele 1 1 1 1 1 1 1 1 1 Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 9 if (zahl > 10) if (zahl) if (zahl != 0) //identisch zum Vorigen if (3*x < 0) if (x*x > 3*y*z) if (fp = fopen("Datei", "r")) if (test(x)) while (*d++ = *s++) ; //Zuweisung! (später) for(i=0; i<27; i++) Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 10 Verwendung von Bedingungen logische Operatoren 1 Empfehlung: auf Lesbarkeit achten! 1 Bei Vergleichen den "konstanteren" Teil auf die rechte Seite des Vergleichsoperators stellen, z.B. for(i=0; i<27; i++) nicht: for(i=0; 27>i; i++) 1 ... verknüpfen Wahrheitswerte zu einem neuen Wahrheitswert 1 1 1 ... sind definiert über Ausdrücken, die zu Wahrheitswerten ausgewertet werden können Kein unnötiger Gebrauch von Wertzuweisungen im Bedingungsteil; Beispiel: fp = fopen("Datei", "r"); if (fp != NULL) wäre ebenfalls möglich gewesen Lieber (aufgrund der Auswerteprioritäten) zuviel Klammern setzen als eine zuwenig! Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 11 Operator NICHT UND / NOT / AND ODER / OR Kontrollstrukturen Schreibweise Schema wahr, wenn ! ! a a ist falsch && a && b beide sind wahr || a || b ein Operand wahr Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg Beispiel ! (a < b) (a==b)&&(b < c) (a<b) || (a>b) 12 2 logische Operatoren Verwendungsbeispiele 1 Bedingungsausdrücke (if-Anweisung , bedingte Schleifen) 1 Prioritäten 1 ! hat höhere Priorität als die Vergleichsoperatoren 1 die Priorität von && ist größer als die von || Verknüpfen von Wahrheitswerten, Variablen und Vergleichsausdrücke 1 1 1 beide haben geringere Priorität als die Vergleichsoperatoren! 1 1 Wichtige Besonderheit bei C/C++ 1 && oder || - Ausdrücke werden strikt von links nach rechts bewertet 1 ... und zwar nur solange (!), bis das Resultat der logischen Verknüpfung feststeht! Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 13 Verwendungsbeispiele Verknüpfen von Wahrheitswerten, Variablen und Vergleichsausdrücke 1 for (i=0; i<lim-1 && (c=getchar()) != '\n' && c != EOF; ++ i) s[i] = c; 1 if (test() && tue_manches() ) // Achtung: tue_manches() wird nur aufgerufen, wenn test() true lieferte!!! Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 15 switch if ( (a < 1.0) && (b > 4.7)) if ( a < 1.0 && b > 4.7 ) 1 do ...... while ((c=getchar()) != 'n' 1 in Wertzuweisungen für Wahrheitswerte: a = a && (b < c) ; a = (a == b) || (b == c); Kontrollstrukturen // ausreichend wäre: && c != 'y') Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 14 1 Typische Anwendungen 1 Fallunterscheidung 1 Auswahlentscheidungen - 1 aus n 1 Anweisungskaskade mit berechnetem Einstieg 1 vollständige Mehrfachverzweigung Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 16 Abarbeitung der switch-Anweisung 1 Syntax 1 switch ( <Ganzzahlausdruck> ) { case <Ganzzahlkonstante>: <Anweisung> // Fall 1 .... case <Ganzzahlkonstante>: <Anweisung> // Fall n default : <Default-Anweisung> // sonst-Fall } 1 <Ganzzahlausdruck>: Ausdruck, der zu einem ganzzahligen Wert ausgewertet wird 1 <Ganzzahlkonstante>: ganze Zahl oder Zeichen , keine strings! 1 <Anweisung> alle in C/C++ erlaubten, formulierbaren Anweisungen, besonders: break; (Verlassen der switchAnweisung) 1 <Default-Anweisung> Sonst-Fall, kann fehlen Kontrollstrukturen 1 switch 1 Bedingungsausdrücke (if-Anweisung , bedingte Schleifen) Kontrollstrukturen if (!( a < 1.0) ) if (!a) if (!test(a)) Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 17 1 Auswerten des <Ganzzahlausdruck> 1 Vergleich mit <Ganzzahlkonstante> der case-Konstante 1 Bei Gleichheit Ausführen der <Anweisung> hinter ":" 1 Anweisungsausführung ohne / mit break; 1 sequentielle Bearbeitung aller folgenden <Anweisungen> bis zum ersten break; 1 oder bis Ende der switch ... } - Anweisung Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 18 3 Beispiel für Verwendung von switch: Realisierung von Auswahl-Menüs Abarbeitung der switch-Anweisung 1 Besonderheit: <Anweisung> bzw. break kann auch fehlen: 1 Zusammenfassen mehrerer Fälle zu gleicher Bearbeitung switch (ausdruck) { case 1: case 2: printf("Fälle 1 & 2 ..."); break; } Cmd = getchar(); switch (Cmd) { case 'h': printf("Hilfe:\n"); printf("p - PKW eingeben\n"; printf("m - Motorrad eingeben\n"; printf("s <Kennzeichen> Daten zum Kennzeichen abrufen\n"; printf("d - alle Daten abrufen\n"; printf("x - Programm verlassen\n\n"; break; case 'p': /* Abfrage der PKW-Daten und Ablegen der Daten */ break; case 'm': /* Abfrage der Motorrad-Daten und Ablegen der Daten */ break; ... case 'd': /* Ausgabe der gesamten erfassten Daten */ break; } 1 keine Übereinstimmung mit Fall-Konstante 1 Ausführen der <Default-Anweisung> 1 fehlt <Default-Anweisung>, Fortsetzung hinter switch ... } Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 19 Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg Zählschleife mit for Zählschleife mit for 1 Wiederholung von Anweisungen abhängig von Zählvariable 1 Besonderheiten / zu beachten 1 typische Anwendungen: 1 Indexlauf, Indizierung von Feldelementen 1 Berechnungen, abhängig von Zählvariable 1 Durchlassausdruck wird vor dem (ersten) Betreten des Schleifenrumpfs überprüft und kann somit zum "Überspringen" des Schleifenrumpfs führen for (<Initialisierungsausdruck> ; // initialisiert Zählvar. <Durchlassausdruck> ; // Bedingung für Durchlauf <Schleifennachlaufausdruck> ) // Operation auf Zählvariable < Anweisung> oder {< Anweisungsfolge>} // Schleifenrumpf Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 20 21 Zähl-Schleife mit for 1 Wert einer globalen Zählvariable ist nach der for-Schleife definiert 1 Die Berechnung innerhalb des Schleifenrumpfs muß der Abbruchbedingung zustreben (Durchlassausdruck = false) Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 22 Zähl-Schleife mit for 1 Komma-Operator ermöglicht Initialisierung mehrerer 1 Der Anweisungsteil kann leer sein (weil schon alles im for-Kopf Variablen bzw. Fortschaltung mehrerer Variablen im Schleifennachlaufausdruck for (j=0, i=1; j<max; i++, j++) ... passiert). Empfehlung: Dies optisch durch eine Zeile nur mit Semikolon verdeutlichen!!! for (i=0; z[i]=q[i]; i++) ; 1 Jeder der drei for-Schleifenabschnitte (Init, Durchlassen, Fortschalten) kann leer sein. Ein fehlender Durchlassausdruck wird als 'wahr' angenommen!!! // z und q Zeichenketten for ( ; ; ) // Formulierung einer unendlichen Schleife --> Die Abbruchbedingung muß somit im Schleifenrumpf stehen (break, return, oä.) Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 23 Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 24 4 Äquivalente Formulierung von for in Form einer while-Schleife Beispiele 1 for (x=10 ; x<=15 ; x++) // Schleifenkopf { } printf("%d %d\n", x, x*x); // Schleifenrumpf // { } Hier eigentlich unnötig <Initialisierungsausdruck> while (<Durchlassausdruck>) 1234 { 56666766668666696666 666 <Anweisungen....> 1 max = feld[0]; <Schleifennachlaufausdruck> // Was wird berechnet ? for ( x=1; x<maxanz ; x=x+1 ) // { if (feld[x] > max) // max = feld[x]; // } Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg } 25 Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg Bedingte Schleifen mit while und do ... while Bedingte Schleifen mit while und do ... while 1 Anwendungen: 1 bedingte Wiederholung einer Anweisung / Anweisungsfolge 1 do ... while besonders für Tastaturabfragen ... bis Eingabe gültig 1 Syntax der do ... while - Schleife: do <Anweisung> bzw. { <Anweisungsfolge> } while (<Bedingungsausdruck>) 1 Syntax der while-Schleife: while ( <Bedingungsausdruck> ) <Anweisung> bzw. {<Anweisungsfolge> } 1 Semantik 1 Solange <Bedingungsausdruck> wahr, führe <Anweisung...> aus. 1 Prüfe vor erstem Durchlauf Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 27 Schleifenrumpf dem Wahrheitswert false zustreben (nicht unbedingt monoton!) Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 28 1 Anwendung 1 möglicher, aber nicht nötiger Anwendungsfall kann das Verlassen einer tiefen Schachtelung sein, wenn Fehler, z.B. bei Funktionsaufrufen, eingetreten sind. 1 for (...) { ... while (...) { ... if (schwerer_fehler) goto fehlerbehandlung; } } fehlerbehandlung: fehler_behandlungs_anweisung ; Schleife terminiert Endlosschleife 1 Als <Bedingungsausdruck> zulässig 1 alle arithmetischen Ausdrücke, 1 alle Zeiger-Ausdrücke und 1 alle unzweideutig in solche konvertierbaren Ausdrücke Kontrollstrukturen Kontrollstrukturen 1 goto marke ; 1 Herkunft: Assembler, Fortran, Basic,... 1 Wirkung: Unbedingte Fortsetzung des Programmlaufs bei der durch Marke angezeigten Stelle innerhalb derselben Funktion 1 Der <Bedingungsausdruck> muß durch die Operationen im 1 sonst: 1 Semantik: 1 Führe den Schleifenrumpf aus, solange der <Bedingungsausdruck> wahr ist 1 Prüfe nach dem (ersten) Durchlauf --> mindestens ein Durchlauf! Unbedingte Fortsetzungen mit goto, continue, break, return Bedingungen für alle Schleifen 1 dann: 26 29 Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 30 5 Beispielprogramm für continue continue 1 Bedeutung 1 Beende aktuellen Durchlauf durch den Schleifenrumpf 1 setze Schleife mit neuem Durchlauf (d.h. ggf. Fortschaltung, Durchlassprüfung) fort 1 // programm anz_ohne, Beispiel für die Anwendung von continue // das Prog. zählt die Zeichenvorkommen != dem Zeichen in c (variable) void main (void) { const maxstr = 20; char str [maxstr] = ”Maximilian”; char c = 'i'; // Vergleichszeichen int anzahl = 0, anz_ohne_c = 0; // index bzw. zählervariable 1 Wirkung 1 Abbrechen des aktuellen Schleifendurchlaufs 1 nicht jedoch der ganzen Schleifenanweisung!!! while (str [anzahl]) // solange string-Ende nicht erreicht { if (str[anzahl++] ==c) continue; // beende Rumpfdurchlauf falls==c anz_ohne_c = anz_ohne_c + 1; // sonst: erhöhe zähler } // enthält Zeichenanzahl ohne c 1 Anwendung 1 eher selten 1 Einsparung von if-Schachtelungen innerhalb des Schleifenrumpfs } Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 31 Beispielprogramm für continue ersetzen? if (str[anzahl++] != c) // erhöhe zähler, wenn zeichen != c anz_ohne_c = anz_ohne_c + 1; // erhöhe feldindex, = gesamtanzahl Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 32 break 1 Wie kann man auf dieses continue verzichten bzw. es ohne Verlust Kontrollstrukturen Kontrollstrukturen 1 Bedeutung / Wirkung: 1 Bricht die Bearbeitung des aktuellen umgebenden switch-Blocks oder der umgebenden Schleife ab. 1 Fortsetzung bei der Anweisung, die dem switch bzw. der Schleife folgt. 1 Anwendung 1 durchaus geläufige Verwendung 1 Realisierung einer echten Mehrfachverzweigung in switch 1 Abbruch einer Schleife beim Eintreten von Ablaufbesonderheiten, evtl. von Fehlern 1 Einsparung von 'Hilfsvariablen', die im Durchlassausdruck immer wieder abgetestet werden müssen sowie das Verlassen einer möglicherweise tiefen IF-Schachtelung 33 Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 34 6