Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen Übersicht 3.1 Die Bibliotheksfunktion scanf() I 3.15 Die switch-Anweisung - Beispiel 3.2 Die Bibliotheksfunktion scanf() II 3.16 Die switch-Anweisung – Bemerkungen zum Beispiel 3.3 Vergleichsoperatoren 3.4 Beispiele mit Vergleichsoperatoren 3.5 Logikoperatoren 3.6 Beispiele mit Logikoperatoren 3.7 Ausdrücke mit unterschiedlichen Operatoren 3.8 Bedingter Ausdruck 3.9 Die if-Anweisung 3.10 Die if-Anweisung – Beispiel 1 3.11 Die if-Anweisung – Beispiel 2 3.12 Die if-Anweisung – Beispiel 3 3.13 Die if-Anweisung – Beispiel 4 3.14 Die switch-Anweisung Prof. Martin Trauth Folie 1 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.1 Die Bibliotheksfunktion scanf() I Die Funktion scanf() ist sozusagen das Gegenstück zu printf(): sie liest Werte von der Standard-Eingabe (das ist bei PCs die Tastatur) und weist sie Variablen zu. Syntax: scanf(<Formatstring>, <Variable/n>) Beispiele: int int1; double doublevar1; Modifikator l (long), weil Variable den Typ double hat scanf(“%i“, &int1) scanf(“%lf“, &doublevar1) Im Gegensatz zu printf() besteht der Formatstring (string = Zeichenkette) üblicherweise nur aus Platzhaltern. Die Platzhalter haben folgende Syntax: %[*][MaxZeichen][Modifikator]Typ Die Typzeichen entsprechen denen für printf(), ebenso die optionalen Modifikatoren. Die Option * führt dazu, dass nur eingelesen, aber dieser Wert keiner Variablen zugewiesen wird. MaxZeichen gibt eine maximale Zeichenanzahl des eingelesenen Werts an. Prof. Martin Trauth Folie 2 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.2 Die Bibliotheksfunktion scanf() II In den Beispielen steht jeweils ein & vor den eigentlichen Variablennamen. Das hat damit zu tun, dass die Funktion die Werte der Variablen ändern soll (printf tat das nicht) und wird später noch genauer erläutert. scanf() muss wissen, wann die Eingabe per Tastatur beendet ist. Die Eingabe muss daher mit der „Wagenrücklauftaste“ (Return oder CR) beendet werden. Oft (aber nicht immer) hat die Enter-Taste am Ziffernblock die gleiche Funktion. Der Programmablauf wird so lange gestoppt bis alle von scanf() erwarteten Werte eingegeben sind. Einen eventuell erwünschten Programmabbruch erreicht man mit strg-C (cntrl-C), d.i. gleichzeitiges Drücken der Tasten Strg und C. Hinweis: Man kann mit scanf() auch mehrere Werte einlesen (z.B. durch Leerzeichen getrennt). Das empfiehlt sich aber nur in Ausnahmefällen, denn jeder Benutzereingabe sollte immer eine Erklärungszeile vorangehen welche Eingabe nun erwartet wird (Ausgabe der Erklärungszeile per printf()). Sonst sieht der Benutzer nur, dass das Programm nicht weiter geht und weiß nicht warum. Bei mehreren Werteingaben hintereinander verliert der Benutzer evtl. die Übersicht. Professionelle Programme (wenn sie etwas taugen) prüfen außerdem stets ob eine Benutzereingabe überhaupt gültig ist und der Benutzer nicht etwa tzrgl eingegeben hat, wo eine Ganzzahl erwartet wurde... scanf() ist eher für einfache Anwendungen zu gebrauchen, wo man sich auf die Eingabequalität verlassen kann. Prof. Martin Trauth Folie 3 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.3 Vergleichsoperatoren Mit Vergleichsoperatoren werden die Werte zweier Operanden miteinander verglichen. Abhängig vom Ergebnis dieses Vergleichs ist der Vergleichsausdruck wahr oder falsch. C arbeitet nicht mit einzelnen Bits. Wahr (true) und falsch (false) werden daher nicht mit Bits sondern mit Zahlenwerten dargestellt: 0 steht für falsch Jeder andere Zahlenwert (auch negative Zahlen) steht für wahr. Das Ergebnis von Vergleichsoperationen ist entweder 0 oder 1 (Typ int) Die Vergleichsoperatoren in C (beziehen sich immer auf die Zahlenwerte der Operanden): Op1 < Op2 Op1 kleiner Op2 Op1 > Op2 Op1 größer Op2 Op1 <= Op2 Op1 kleiner oder gleich Op2 Op1 >= Op2 Op1 größer oder gleich Op2 Op1 == Op2 Op1 gleich Op2 (nur Wertevergleich – keine Zuweisung!) Op1 != Op2 Op2 ungleich Op2 Prof. Martin Trauth Folie 4 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.4 Beispiele mit Vergleichsoperatoren 3<x Wahr, wenn x größer als 3 ist. Bei x= 3,001 wäre das z.B. schon der Fall. a>c Wahr, wenn der Wert von a größer als der Wert von c ist. 48 <= ‘0‘ Wahr, denn der Zahlenwert des Zeichens 0 ist 48 (s. ASCII-Tabelle). ‘A‘ <= ‘a‘ Wahr, denn Großbuchstaben haben kleinere Zahlenwerte als Kleinbuchstaben. ‘M‘ == ‘m‘ Falsch ‘0‘ != 0 Wahr ‘\0‘ != 0 -0.348 < -0.3 1 == 1.0 Falsch Wahr Wahr, denn es kommt nur auf die Zahlenwerte an, nicht auf den Datentyp Prof. Martin Trauth Folie 5 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.5 Logikoperatoren Um Logikoperationen durchführen zu können stellt C die elementaren Logikoperatoren UND (AND), ODER (OR) und NICHT (NOT) zur Verfügung. Die Logikwerte wahr und falsch werden durch Zahlenwerte „ungleich 0“ (wahr) und 0 (falsch) dargestellt. Die Logikoperatoren in C: Op1 && Op2 Op1 UND Op2 Op1 & Op2 bitweise Op1 UND Op2 Op1 || Op2 Op1 ODER Op2 Op1 | Op2 bitweise Op1 ODER Op2 !Op1 NICHT Op1 ~Op1 bitweise Negation von Op1 Op1^Op2 bitweises EX-OR (exklusives ODER) ! (NICHT) hat die höchste Priorität unter den Logikoperatoren, gefolgt von && und || . Für bitweise Verarbeitung gilt die gleiche Reihenfolge. Ansonsten werden Reihenfolgen binärer Operatoren (solche mit 2 Operanden) von links nach rechts ausgewertet. Prof. Martin Trauth Folie 6 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.6 Beispiele mit Logikoperatoren 3 && x Wahr, wenn x nicht 0 ist. 0xAB73 & 0xFF00 1 || x Immer wahr. 0xAB73 | 0xFF00 Hat das Ergebnis 0xAB00, da die einzelnen Bits UND-verknüpft werden 0 || x Wahr, wenn x nicht 0 ist. Hat das Ergebnis 0xFF73, da die einzelnen Bits ODER-verknüpft werden !k Wahr (1), falls k = 0, sonst falsch (0) !(a || b) Falsch (0), wenn entweder a oder b wahr ist (oder beide). Das ODER wird zuerst ausgewertet (Klammer!). ~ 0xFF00 !0 Hat das Ergebnis 1 (wahr) Hat das Ergebnis 0x00FF, da alle Bits „umgedreht“ werden. Aus 1 wird 0, aus 0 wird 1. 0xAB73 ^ 0xFF00 Hat das Ergebnis 0x5473. Das Ex-OR hat dann wahr (1) als Ergebnis wenn nur eins von beiden Bits 1 ist. Sind beide 0 oder beide 1, dann ist das Ergebnis falsch (entsprechendes Ergebnis-Bit ist 0) Hinweis: bitweise Logikoperationen erfordern Operanden von Typ unsigned integer (positive Ganzzahlen), um gut interpretierbare Ergebnisse zu erhalten. Prof. Martin Trauth Folie 7 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.7 Ausdrücke mit unterschiedlichen Operatoren Man kann in C sehr komplexe Ausdrücke bilden, da man arithmetische, Vergleichs- und Logikoperatoren fast unbegrenzt kombinieren kann. Beispiel: 2. * pi <= winkel1 || umfang – 10. == 5.3 && freigabe15 Wie in der Mathematik werden Teilausdrücke in Klammern zuerst bearbeitet. Bei verschachtelten Klammern werden zuerst die innersten Klammern ausgewertet. Neben den bereits erwähnten Prioritäten, wie der Punkt-vor-Strich-Regel bei Arithmetikoperatoren, gelten folgende Prioritäten in absteigender Reihenfolge: 1. sog. unitäre Operatoren, die nur auf einen Operanten wirken (z.B. !) 2. Arithmetikoperatoren 3. Vergleichsoperatoren (<, >, <= und >= haben höhere Priorität als == und !=) 4. Logikoperatoren 5. Zuweisungen In dem Beispiel oben werden also zuerst die arithmetischen Operationen 2. * pi und umfang – 10. ausgeführt. Danach folgen die Vergleiche (<= und ==), dann die UND-Verknüpfung (&&) und zum Schluss das ODER (||). Das Ergebnis des Ausdrucks ist also ein Logikwert (1 oder 0). Falls dieser Wert einer Variablen zugewiesen werden sollte, würde das noch folgen. Empfehlung: Klammern verwenden wegen Übersichtlichkeit. Prof. Martin Trauth Folie 8 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.8 Bedingter Ausdruck Der bedingte Ausdruck verwendet einen Logikausdruck für eine Entscheidung. Syntax: <Logikausdruck> ? <1. Ausdruck> : <2. Ausdruck> Beispiel: resultat = x > y ? a + 309 : c – 5.5 Funktion: Wenn der Ausdruck links vom Fragezeichen wahr ist, wird der 1. Ausdruck rechts davon als Ergebnis (Wert des Gesamtausdrucks) verwendet, wenn er falsch ist der 2. Ausdruck. Der Doppelpunkt trennt die beiden Ausdrücke. Beispiel für eine typische Anwendung: printf(“Die Versandkosten betragen %.2f Euro“, warenwert >= 100. ? 0. : 5.); Wenn der Warenwert (in Variable warenwert) größer oder gleich 100. ist, dann wird die 0. an Stelle des Platzhalters in der printf()-Funktion gesetzt. Ist er kleiner 0., dann wird die 5. verwendet. Der bedingte Ausdruck ist die einfachste Form von Verzweigungen in C-Programmen. Prof. Martin Trauth Folie 9 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.9 Die if-Anweisung Die if-Anweisung ist sehr vielseitig und flexibel. Sie wird daher für die Programmierung von Verzweigungen (Entscheidungen) in C am meisten verwendet. Syntax: if (<Logikausdruck 1>) <Anweisung 1 (oder Block1)> else if (<Logikausdruck 2>) <Anweisung 2 (oder Block 2)> ... else if (<Logikausdruck n>) <Anweisung n (oder Block n)> else <Alternativ-Anweisung (oder Block)> Prof. Martin Trauth Folie 10 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.10 Die if-Anweisung – Beispiel 1 Ein Programmabschnitt als Beispiel: if (warenwert >= 1000.) { // wenn Warenwert mindestens 1000 Euro fracht = 0.; // keine Frachtkosten bonus = 50.; // Bonus 50 Euro } else if (warenwert >= 500.) { // wenn Warenwert mindestens 500 Euro fracht = 0.; // keine Frachtkosten bonus = 0.; // aber auch kein Bonus } else { // bei kleinerem Warenwert fracht = 10.; // 10 Euro Frachtkosten bonus = 0.; } Der erste Logikausdruck in einer if..else if..else-Kette der wahr ist, führt zur Abarbeitung der entsprechenden Anweisung oder eines Blocks von Anweisungen (eingefasst in geschweifte Klammern). Nur diese Anweisung oder dieser Block werden ausgeführt. Danach wird das Programm hinter dem if...else if...else-Abschnitt fortgesetzt. Prof. Martin Trauth Folie 11 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.11 Die if-Anweisung – Beispiel 2 Die else if- und else- Abschnitte sind optional, d.h. sie können auch entfallen. Ein Beispiel mit reinem if-Block, das zum gleichen Ergebnis führt wie Beispiel 1. bonus = 0; // Anfangswert setzen fracht = 10. if (warenwert >= 1000.) // wenn Warenwert mindestens 1000 Euro bonus = 50.; // Bonus 50 Euro if (warenwert >= 500.) // wenn Warenwert mindestens 500 Euro fracht = 0.; // keine Frachtkosten Dieses Programm ist kompakter, aber weniger übersichtlich. Man muss schauen wo und warum die Anfangswerte überschrieben werden. Da den if-Anweisungen nur einzelne Anweisungen folgten, wurden keine Blöcke in geschweiften Klammern benötigt. Hinweis: direkt nach dem Logikausdruck in der if-Anweisung folgt noch kein Semikolon, denn die Anweisung ist noch nicht „komplett“ ohne die nachfolgende Anweisung. Prof. Martin Trauth Folie 12 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.12 Die if-Anweisung – Beispiel 3 Man kann if-Anweisungen schachteln, d.h. die Anweisung in einem if-Block ist wieder eine if-Anweisung. bonus = 0; // Anfangswert setzen fracht = 10. if (warenwert >= 500.) { // wenn Warenwert mindestens 500 Euro fracht = 0.; // keine Frachtkosten if (warenwert >= 1000.) // wenn Warenwert mindestens 1000 Euro bonus = 50.; // 50 Euro Bonus } Das zweite if befindet sich innerhalb eines Blocks, da auf das erste if zwei Anweisungen folgen: die Zuweisung von 0. an die Variable fracht und die zweite if-Anweisung. Die einzelne Anweisung hinter dem zweiten if benötigt keinen Block. Man könnte aber auch einen Block mit nur einer Anweisung schreiben. C erlaubt das. Auch innerhalb von else if- oder else-Blöcken können neue if- else if- else-Anweisungen stehen. Hinweis: Durch geeignetes Plazieren der geschweiften Klammern und Einrücken von Programmzeilen sollte immer deutlich gemacht werden, welche Anweisungen zu einer if- else if- else-Konstruktion gehören. Prof. Martin Trauth Folie 13 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.13 Die if-Anweisung – Beispiel 4 Hier ein Beispiel für einen fehlerhafte Programmtext mit if-Anweisung if (warenwert >= 500.) { // wenn Warenwert mindestens 500 Euro fracht = 0.; // keine Frachtkosten if (warenwert >= 1000.) // wenn Warenwert mindestens 1000 Euro bonus = 50.; // 50 Euro Bonus } else { bonus = 0; fracht = 10. } Eigentlich gut gedacht: statt des Setzens von Anfangswerten wird die Zuweisung der Werte von fracht und bonus im Falle „Warenwert unter 500 Euro“ in einen else-Block verlegt. Das macht den Programmtext strukturierter. Aber es wurde etwas übersehen: Bei Warenwerten zwischen 500 (inklusive) und 1000 wird die innere if-Anweisung nicht ausgeführt (weil Logikausdruck falsch). Auch der else-Block wird nicht ausgeführt, da dieses else nur zur äußeren if-Anweisung gehört. Die Variable bonus ist daher nicht definiert. Wenn sie später verwendet wird, hat sie sehr wahrscheinlich unsinnige Werte. Prof. Martin Trauth Folie 14 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.14 Die switch-Anweisung Die switch-Anweisung ist eine weitere Möglichkeit Fälle zu unterscheiden und das Programm zu verzweigen. Sie verwendet keine Logikausdrücke sondern Zahlenwerte (Ganzzahlen) zur Entscheidung. Syntax: switch (<Ganzzahlausdruck>) { case <Ganzzahlkonstante 1> : Switch benötigt immer einen Block. <Anweisung(en)> case <Ganzzahlkonstante 2> : <Anweisung(en)> ... Die Doppelpunkte kennzeichnen die caseSchlüsselworte als Marken (labels). Gleiches gilt für die defaut-Marke. case <Ganzzahlkonstante n> : <Anweisung(en)> default: <Anweisung(en)> } Ende des Switch-Blocks. Funktion: der Programmablauf verzweigt zu der case-Marke, deren Zahlenwert dem Ganzzahlausdruck nach switch entspricht. Paßt keiner der Zahlenwerte, dann wird zur default-Marke verzweigt. Die default-Marke ist optional, man kann sie also auch weglassen. Prof. Martin Trauth Folie 15 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.15 Die break-Anweisung Wenn die switch-Anweisung zu einer Marke verzweigt hat, läuft das Programm von dort aus bis zum Ende des switchBlocks weiter. Das ist oft unerwünscht, denn dann werden auch alle die Anweisungen ausgeführt, die hinter den folgenden case-Marken stehen. Auch die Anweisungen hinter der default-Marke würden ausgeführt. Will man das vermeiden, dann setzt man break-Anweisungen hinter die Anweisungen, die nur zu einer caseAlternative gehören. Die break-Anweisung bewirkt, dass das Programm den switch-Block verlässt und dahinter weitergeführt wird. Syntax: break; Hinweis: Die break-Anweisung wird nicht nur im Zusammenhang mit switch verwendet, sondern ist vielseitiger. Sie unterbricht stets einen bestimmten Vorgang. Prof. Martin Trauth Folie 16 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.16 Die switch-Anweisung – Beispiel /* Beispiel für Switch-Anweisung, switch1.c */ /* Das Programm berechnet die Tage in einem Monat*/ Fortsetzung: case 4: #include <stdio.h> case 6: case 9: case 11: main() { int jahr, monat, tage; tage = 30; printf("\nBitte Jahr eingeben: "); break; default: scanf("%i", &jahr); tage = 31; printf("\nBitte Monat eingeben: "); scanf("%i", &monat); } // Ende switch-Block if (monat >= 1 && monat <= 12 && jahr > 1582) { printf("\n%i hat der %i. Monat %i Tage\n", jahr, monat, tage); switch (monat) { } // Ende if-Block case 2: else if (!((jahr%100)%4) && (jahr%100) || !(jahr%400)) tage = 29; // Schaltjahr! else printf("\nFalsche Datumseingabe!"); } tage = 28; break; // switch-Block verlassen Prof. Martin Trauth Folie 17 / 19 Informatik 1 – Teil 3: Vergleichen, Logikoperatoren, Verzweigungen 3.17 Die switch-Anweisung – Bemerkungen zum Beispiel Der Ausdruck (monat >= 1 && monat <= 12 && jahr > 1582) in der 1. if-Anweisung stellt sicher, dass nur gültige Monate (in Zahlen) und Jahre nach der gregorianischen Kalenderreform eingegeben werden. Der etwas komplizierte Ausdruck (!((jahr%100)%4) && (jahr%100) || !(jahr%400)) des zweiten if ermittelt die Schaltjahre. Dazu werden diverse Teilbarkeiten überprüft (nach den Regeln von Papst Gregor). Die Fälle der Monate 4, 6, 9 und 11 münden alle über die entsprechenden case-Marken in die Anweisung tage= 30; Danach wird mit break; der switch-Block verlassen. Allgemeiner Hinweis zur Verwendung der switch-Anweisung: Sie funktioniert auch mit einzelnen Buchstaben, da diesen (ganze) Zahlenwerte zugeordnet sind. Eine case-Marke kann also z.B. lauten: case ‘B‘: Genauso hätte man schreiben können: case 66: denn 66 ist der ASCII-Zahlenwert des Zeichens B. Prof. Martin Trauth Folie 18 / 18