Programmiersprachen Einführung in C Teil 5: Kontrollstrukturen Prof. Dr. Jörg Schwenk Lehrstuhl für Netz- und Datensicherheit Gliederung Programmiersprachen 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 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 2 1 Kontrollstrukturen 1 Ohne Kontrollstrukturen: 1 lineare Programme 1 sequentielle Ausführung der Anweisungen 1 Probleme: 1 1 1 1 1 keine Reaktion auf äußere und innere Bedingungen möglich keine Ausnahmebehandlung / Fehlerbehandlung möglich starrer Ablauf, keine Wiederholungen Parametrisierung eingeschränkt arme Algorithmen-Schemata für Programmentwurf 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 Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 3 Verzweigung mit IF 1 allgemeine Formen bedingter Anweisungen ( <Bedingungsausdruck> <Anweisung> ; ) ( <Bedingungsausdruck> <Anweisung> ; else <Anweisung> ; ) if if 1 // Einzelanweisung // Einzelanweisung // Einzelanweisung Behandlung von Anweisungsfolgen if ( <Bedingungsausdruck> ) <Anweisungsfolge> { // Anweisungsfolge in { ... } } if ( <Bedingungsausdruck> ) <Anweisungsfolge> { // Anweisungsfolge in { ... } } else { <Anweisungsfolge> // Anweisungsfolge in { ... } } Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 4 2 Beispiele für Fallunterscheidungen 1 Schleichwegfahrt: Fahrt Richtung Osten, wenn Tageszeit zwischen 7 und 19 Uhr und Fußgängerampel auf rot, dann fahre Schleichweg, sonst fahre geradeaus. 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 U mwälzpumpe aus Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 5 Beispiel: Zahlenklassifizieren void main () { const int zehn = 10; int wert = 0; printf(”\ngib eine Zahl ein : ”); scanf("%d", &wert); if ( wert == zehn ){ printf(”der Wert ist zehn ”); // falls Wert gleich (Vorsicht !!) } 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 ”); } } } Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 6 3 Beobachtungen (bei großer Schachtelungstiefe) 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 Vergleiche und logische Operatoren 1 Vergleichsoperatoren und logische Operatoren liefern als Ergebnis ... 1 1 in C++ Wahrheitswerte (Datentyp: bool), in C jedoch einfach einen Zahlenwert, welcher entsprechend interpretiert wird wahr / falsch true / false ≠0 / 0 (interne Realisierung) 1 Vergleichsoperatoren 1 1 gleich | ungleich|kleiner |größer |kleiner oder gleich |größer oder gleich == != < > <= >= 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 4 Vergleiche und logische Operatoren 1 Besonderheit in C/C++ 1 1 1 1 Jeder Ausdruck kann als Wahrheitswert interpretiert werden Daher: if (3*x/12) zulässig; In Abhängigkeit von x wird verzweigt Insbesondere:if ( x = 12 ) ebenfalls zulässig; Konsequenzen??? Wertzuweisung hat niedrigere Priorität als Vergleichsoperatoren! if ( (c=getchar()) != 'n') // Klammerung nötig! Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 9 Verwendung von Bedingungen 1 Beispiele 1 1 1 1 1 1 1 1 1 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 5 Verwendung von Bedingungen 1 Empfehlung: auf Lesbarkeit achten! 1 1 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++) 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 logische Operatoren 1 ... verknüpfen Wahrheitswerte zu einem neuen Wahrheitswert 1 ... sind definiert über Ausdrücken, die zu Wahrheitswerten ausgewertet werden können Operator UND Schreibweise Schema wahr, wenn ! ! a / NOT a ist falsch && a && b beide sind wahr / AND ODER / OR NICHT Kontrollstrukturen || a || b Beispiel ! (a < b) (a==b)&&(b < c) ein Operand wahr (a<b) || (a>b) Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 12 6 logische Operatoren 1 Prioritäten 1 ! hat höhere Priorität als die Vergleichsoperatoren 1 die Priorität von && ist größer als die von || 1 beide haben geringere Priorität als die Vergleichsoperatoren! 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 1 Bedingungsausdrücke (if-Anweisung , bedingte Schleifen) Verknüpfen von Wahrheitswerten, Variablen und Vergleichsausdrücke 1 1 1 1 1 1 if (!( a < 1.0) ) if (!a) if (!test(a)) if ( (a < 1.0) && (b > 4.7)) if ( a < 1.0 && b > 4.7 ) // ausreichend wäre: do ...... while ((c=getchar()) != 'n' && c != 'y') in Wertzuweisungen für Wahrheitswerte: a = a && (b < c) ; a = (a == b) || (b == c); Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 14 7 Verwendungsbeispiele 1 Bedingungsausdrücke (if-Anweisung , bedingte Schleifen) Verknüpfen von Wahrheitswerten, Variablen und Vergleichsausdrücke 1 1 for (i=0; i<lim-1 && (c=getchar()) != '\n' && c != EOF; ++ i) s[i] = c; if (test() && tue_manches() ) // Achtung: tue_manches() wird nur aufgerufen, wenn test() true lieferte!!! Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 15 switch 1 Typische Anwendungen 1 1 1 1 Fallunterscheidung Auswahlentscheidungen - 1 aus n Anweisungskaskade mit berechnetem Einstieg vollständige Mehrfachverzweigung Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 16 8 switch 1 Syntax 1 1 1 1 1 switch ( <Ganzzahlausdruck> ) { case <Ganzzahlkonstante>: <Anweisung> // Fall 1 .... case <Ganzzahlkonstante>: <Anweisung> // Fall n default : <Default-Anweisung> // sonst-Fall } <Ganzzahlausdruck>: Ausdruck, der zu einem ganzzahligen Wert ausgewertet wird <Ganzzahlkonstante>: ganze Zahl oder Zeichen , keine strings! <Anweisung> alle in C/C++ erlaubten, formulierbaren Anweisungen, besonders: break; (Verlassen der switchAnweisung) <Default-Anweisung> Sonst-Fall, kann fehlen Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 17 Abarbeitung der switch-Anweisung 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 9 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; } 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 Beispiel für Verwendung von switch: Realisierung von Auswahl-Menüs 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; } Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 20 10 Zählschleife mit for 1 Wiederholung von Anweisungen abhängig von Zählvariable 1 typische Anwendungen: 1 Indexlauf, Indizierung von Feldelementen 1 Berechnungen, abhängig von Zählvariable 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 21 Zählschleife mit for 1 Besonderheiten / zu beachten 1 Durchlassausdruck wird vor dem (ersten) Betreten des Schleifenrumpfs überprüft und kann somit zum "Überspringen" des Schleifenrumpfs führen 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 11 Zähl-Schleife mit for 1 Komma-Operator ermöglicht Initialisierung mehrerer Variablen bzw. Fortschaltung mehrerer Variablen im Schleifennachlaufausdruck for (j=0, i=1; j<max; i++, j++) ... 1 Jeder der drei for-Schleifenabschnitte (Init, Durchlassen, Fortschalten) kann leer sein. Ein fehlender Durchlassausdruck wird als 'wahr' angenommen!!! 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 Zähl-Schleife mit for 1 Der Anweisungsteil kann leer sein (weil schon alles im for-Kopf passiert). Empfehlung: Dies optisch durch eine Zeile nur mit Semikolon verdeutlichen!!! for (i=0; z[i]=q[i]; i++) ; Kontrollstrukturen // z und q Zeichenketten Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 24 12 Beispiele 1 for (x=10 ; x<=15 ; x++) // Schleifenkopf { printf("%d %d\n", x, x*x); // Schleifenrumpf } // { } Hier eigentlich unnötig 1234 56666766668666696666 666 1 max = feld[0]; // 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 Äquivalente Formulierung von for in Form einer while-Schleife <Initialisierungsausdruck> while (<Durchlassausdruck>) { <Anweisungen....> <Schleifennachlaufausdruck> } Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 26 13 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 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 Bedingte Schleifen mit while und do ... while 1 Syntax der do ... while - Schleife: do <Anweisung> bzw. { <Anweisungsfolge> } while (<Bedingungsausdruck>) 1 Semantik: 1 Führe den Schleifenrumpf aus, solange der <Bedingungsausdruck> wahr ist 1 Prüfe nach dem (ersten) Durchlauf --> mindestens ein Durchlauf! Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 28 14 Bedingungen für alle Schleifen 1 Der <Bedingungsausdruck> muß durch die Operationen im Schleifenrumpf dem Wahrheitswert false zustreben (nicht unbedingt monoton!) 1 dann: 1 sonst: 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 Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 29 Unbedingte Fortsetzungen mit goto, continue, break, return 1 goto marke ; 1 Herkunft: Assembler, Fortran, Basic,... 1 Wirkung: Unbedingte Fortsetzung des Programmlaufs bei der durch Marke angezeigten Stelle innerhalb derselben Funktion 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 ; Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 30 15 continue 1 Bedeutung 1 Beende aktuellen Durchlauf durch den Schleifenrumpf 1 setze Schleife mit neuem Durchlauf (d.h. ggf. Fortschaltung, Durchlassprüfung) fort 1 Wirkung 1 Abbrechen des aktuellen Schleifendurchlaufs 1 nicht jedoch der ganzen Schleifenanweisung!!! 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 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 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 } Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 32 16 Beispielprogramm für continue 1 Wie kann man auf dieses continue verzichten bzw. es ohne Verlust ersetzen? if (str[anzahl++] != c) // erhöhe zähler, wenn zeichen != c anz_ohne_c = anz_ohne_c + 1; // erhöhe feldindex, = gesamtanzahl Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 33 break 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 Kontrollstrukturen Quelle: R. Eck und U. Wienkop Programmieren I, GSO FH Nürnberg 34 17