====== Entscheidungen treffen ====== * Wie trifft man eine Entscheidung? * Den Programmablauf beeinflussen * Boolische Ausdrücke formulieren * Boolische Ausdrücke verknüpfen ===== Wie trifft man eine Entscheidung? ===== Wenn es sich in diesem Kapitel wieder um Datentypen dreht, dann könnte man sich natürlich fragen, ob der Autor dieses Tutorials sonst nichts zu erzählen hat. Tatsächlich ist es so, dass sich immer wieder alles darum dreht, wie man die Bits und Bytes in seinem Rechner interpretiert. Und es zeigt auch, dass die "schweren" Programmiersprache C und C++ gar nicht so schwer sind, weil sich eigentlich alles immer wieder um Werte und Datentypen - also die Weise, wie man einen Wert interpretiert - dreht. Um eine Entscheidung zu treffen, muss man einen Wert interpretieren und zwar in der Form, ob man ihn für passend oder unpassend hält. Ob man das eine tut oder das andere. Ja oder nein, Strom an oder aus, wahr oder falsch. Nur mit Aussagen zu arbeiten, die Wahr (true) oder Falsch (false) sind, nennt man Boolesche Algebra. Ein Ausdruck, der sich damit beschäftigt, ob eine Aussage wahr oder falsch ist, nennt man booleschen Ausdruck. Was auch immer es für Datentypen gibt, für C ist die Sache sehr einfach: Ist der Wert 0, so wird das als false interpretiert, nein, Strom aus, unpassend interpretiert. Hat man einen beliebigen Wert, der sich von 0 unterscheidet, so wird das als passend, Strom an, ja und true. So trifft man eine Entscheidung: Ist der Wert ungleich 0, dann tue etwas, sonst tue etwas anderes. ===== Den Programmablauf beeinflussen ===== Den Programmverlauf steuert man wie zuvor beschrieben. Das Schlüsselwort dafür heißt "if", gefolgt von einem Ausdruck in runden Klammern: #include int main( void ) { int decision = 1; if( decision ) // wenn decision ungleich 0 ist, dann... { printf( "decision ist ungleich 0\n" ); } return 0; } Kompilieren wir das Programm und führen es aus, so sehen wir den Text ''decision ist ungleich 0'' auf dem Monitor. Ändern wir nun die Zeile int decision = 1; auf int decision = 0; so erscheint keine Ausgabe mehr: Das Programm führt die Befehle hinter dem Ausdruck, der die Bedingung beschreibt, nicht mehr aus. Wir schrieben zuvor aber "Ist der Wert ungleich 0, dann tue etwas, sonst tue etwas anderes." Es gibt also die Möglichkeit etwas zu tun, wenn der Wert ''decision'' 0 entspricht. Hierfür wird ein 'else' hinter die Anweisungen geschrieben, wo genauso in geschweiften Klammern Anweisungen stehen können. Den Programmabschnitt der durchgeführt wird, wenn der boolesche Ausdruck ''true'' ergibt, nennt man Then-Part (der "Dann-Abschnitt") und den Abschnitt, der ausgeführt wird, wenn der boolesche Ausdruck ''false'' ergibt, nennt man Else-Part (der "Sonst-Abschnitt"). Im nachfolgenden Beispielquelltext habe ich die jeweiligen Parts durch einen Kommentar (Textpassagen zwischen /* und */ werden vom Compiler ignoriert) markiert. Wir können somit jetzt den Programmablauf anhand einer Variablen verzweigen. #include int main( void ) { int decision = 1; if( decision ) /* "Then-Part" */ { printf( "decision ist ungleich 0\n" ); } else /* "Else-Part" */ { printf( "decision ist gleich 0\n" ); } return 0; } Der Else-Part ist optional, kann also weggelassen werden. Der Then-Part hingegen muss nach dem ''if'' geschrieben werden. ===== Boolische Ausdrücke formulieren ===== Wir wissen nun, dass wir Entscheidungen mit dem Vergleich gegen 0 durchführen können. Bisher haben wir Existenzabfragen formuliert. Warum die so heißen, erfahren wir bald. Das kann allerdings teilweise zu recht verkorkstem Denkweisen führen: Wenn wir in unseren Beispielprogramm eine Variable mit dem Wert 7 vergleichen wollen, dann müssen wir einen Ausdruck finden, der nur dann ungleich 0 ist, wenn die Variable 7 ist. Mit unseren bisherigen Mitteln können wir nur folgendes schreiben: Wir ziehen den gesuchten Wert 7 ab, dann ist der Ausdruck ''decision - 7'' genau dann falsch, wenn decision den gesuchten Wert entspricht: #include int main( void ) { int decision = 7; if( decision - 7 ) { printf( "Der ungewünschte Fall: decision ist nicht 7\n" ); } else { printf( "Der gewünschte Fall: decision ist gleich 7\n" ); } return 0; } Es ist also möglich, aber schön ist das natürlich nicht. Daher gibt es neben den mathematischen Operatoren auch boolesche Operatoren, mit deren Hilfe man Werte vergleichen kann: ^ Operator ^ Bedeutung ^ | == | wahr, wenn gleich | | != | wahr, wenn ungleich | | > | wahr, wenn linke Seite größer als rechte Seite | | >= | wahr, wenn linke Seite größer oder gleich als rechte Seite | | < | wahr, wenn linke Seite kleiner als rechte Seite | | <= | wahr, wenn linke Seite kleiner oder gleich als rechte Seite | | ! | wahr, wenn der Ausdruck an der rechten Seite falsch ist | Die Operatoren geben einen booleschen Wert zurück, nämlich ''true'' oder ''false'', also genau das, was wir benötigen, um eine Entscheidung zu treffen. Wir können unsere Frage jetzt also leichter und verständlicher formulieren: #include int main( void ) { int decision = 7; if( decision == 7 ) { printf( "Der gewünschte Fall: decision ist gleich 7\n" ); } else { printf( "Der ungewünschte Fall: decision ist nicht 7\n" ); } return 0; } Nehmen wir noch ein ein paar Vergleiche als Beispiel, damit man sie mal gesehen hat: ^ Beispiel ^ Bedeutung ^ | ''if( decision > 7 )'' | Wenn ''decision'' größer als 7 ist, dann...| | ''if( decision <= 7 )'' | Wenn ''decision'' kleiner oder gleich 7 ist, dann... | | ''if( !(decision <= 7) )'' | Wenn ''decision'' **nicht** kleiner oder gleich 7 (also größer als 7) ist , dann... | | ''if( !(decision > 7) )'' | Wenn ''decision'' **nicht** größer als 7 (also kleiner oder gleich 7) ist , dann... | ===== Schachteln von Abfragen ===== If-Abfragen kann man auch schachteln: #include int main( void ) { int mayBeDigit = '0'; if( mayBeDigit >= '0' ) { if( mayBeDigit <= '9' ) { printf( "'%c' ist eine Ziffer\n", mayBeDigit ); } else { printf( "'%c' ist keine Ziffer\n", mayBeDigit ); } } else { printf( "'%c' ist keine Ziffer\n", mayBeDigit ); } return 0; } Die booleschen Vergleichsoperatoren (==, !=, > usw.) funktionieren genauso wie mathematische Operatoren: Es wird ein Ergebnis zurückgeliefert, das entweder 0 (für false) oder 1 (für true) ist. Damit lassen sich auch Ausdrücke schreiben wie: int a = 4 > 1; a ist nun 1 (true). Die logische Negation (''!-Operator'') entspricht der mathematischen Negation. ''-a'' ist der negative Wert von ''a''. ''!a'' ist das logische Gegenteil von ''a'': aus ''true'' wird ''false'', aus ''false'' wird ''true''. ===== Boolische Ausdrücke verknüpfen ===== Das vorherige Beispiel zeigt ein neues Problem auf, um das wir uns noch schnell kümmern wollen: Wir stellen zwei Fragen, die eigentlich zusammen gehören, um eine Entscheidung zu treffen. Weil wir zwei Fragen stellen, bekommen wir auch zwei Möglichkeiten, die Antwort 'false' zu erhalten und hier wird in beiden Fall gleich reagiert. Es wird also Quelltext wiederholt, was man möglichst vermeiden sollte. Um diese beiden Fragen zusammenzuführen, müssen wir sie zu einer großen Frage verknüpfen. Diese Verknüpfung von Ausdrücken nennt man [[theory:logic:conjunction|Junktion]]. In C werden zwei Junktoren verwendet: das //logische Und// (auch logische Multiplikation) und das //logische Oder// (auch logische Addition genannt). Die Operatoren heißen hier ''&&'' und ''||'' und sie geben wieder einen booleschen Wert zurück. Im obenstehenden Beispiel muss ein Wert größer als '0' sein oder der '0' entsprechen **UND** die der Wert muss kleiner als '9' sein oder der '9' entsprechen, **dann** ist es eine Ziffer, **sonst** nicht. Der ''&&''-Operator liefert nur dann ''true'', wenn beide Ausdrücke links und rechts ''true'' ergeben, sonst false - einer reicht nicht. Der ''||''-Operator hingegen liefert ''true'' wenn mindestens einer der beiden Ausdrücke ''true'' ergibt - hier reicht eine Seite. Formulieren wir das Programm in C: #include int main( void ) { int mayBeDigit = '0'; if( mayBeDigit >= '0' && mayBeDigit <= '9' ) { printf( "'%c' ist eine Ziffer\n", mayBeDigit ); } else { printf( "'%c' ist keine Ziffer\n", mayBeDigit ); } return 0; } Da wir nur noch eine Frage haben, müssen wir uns auch nur noch um einen Then-Part und einen Else-Part kümmern, die Wiederholung fällt damit weg. Wenn wir die Frage andersherum formulieren, drehen sich alle Operatoren um: Wenn der Wert kleiner als '0' ist **ODER** größer als '9', **dann** ist es **keine** Ziffer, **sonst** ist es eine Ziffer: #include int main( void ) { int mayBeDigit = '0'; if( mayBeDigit < '0' || mayBeDigit > '9' ) { printf( "'%c' ist keine Ziffer\n", mayBeDigit ); } else { printf( "'%c' ist eine Ziffer\n", mayBeDigit ); } return 0; } Man sollte Fragen so formulieren, dass sie leicht verständlich sind. if( mayBeDigit >= '0' && mayBeDigit <= '9' ) entspricht if( !(mayBeDigit < '0' || mayBeDigit > '9') ) aber die erste Variante ist für die meisten vermutlich leichter zu verstehen. ====== Ziel dieser Lektion ====== Du solltest nun wissen, wann ein Wert als ''true'' (wahr) interpretiert wird und wann als ''false'' (falsch) und Du kannst boolesche Ausdrücke mit Vergleichen und Negationen formulieren. Du solltest Abfragen machen können und boolesche Werte miteinander verknüpfen können, um aufwendigere Abfrage zusammen zu fassen. Nimm Dir etwas Zeit, um einige kleine Programme mit Vergleichen zu schreiben, auszuprobieren und die Resultate nachzuvollziehen. Danach schauen wir uns in der [[c:tutorial:loops|nächsten Lektion Wiederholungen]] an.