Der Wert des ternären Ausdrucks in C
Ein ternärer Ausdruck hat auch einen Wert. Es handelt sich um den Wert des zuletzt ausgewerteten Operanden.
Wir sehen jeden der beiden Werte »0« oder »0.0« als Null an. Wir sagen auch, daß ein Wert ungleich Null ist, wenn er nicht gleich »0« oder »0.0« ist; der Wert eines Zeichenfolgenliterals ist immer ungleich Null.
Auswertung eines ternären Ausdrucks
Bei der Auswertung eines ternären Ausdrucks wird zuerst der erste Operand ausgewertet.
▶ Wenn der bei der Auswertung des ersten Operanden erhaltene Wert ungleich Null ist, dann wird der zweite Ausdruck ausgewertet, und der dritte Ausdruck wird nicht ausgewertet, der Wert des gesamten ternären Ausdrucks ist dann der Wert des zweiten Operanden,
▶ sonst wird der dritte Ausdruck ausgewertet, und der zweite Ausdruck wird nicht ausgewertet, und der Wert des gesamten ternären Ausdrucks ist der Wert des dritten Operanden.
So ergibt sich als Wert des Ausdrucks »( 3 ? 4 : 5 )« der Wert »4«, denn da der Wert des ersten Ausdrucks der Wert »3« ist und dieser Wert ungleich Null ist, ist der Wert des gesamten Ausdrucks der Wert des Operanden links vom Doppelpunkt »:«, also »4«.
Als Wert des Ausdrucks »( 0 ? 1 : 2 )« ergibt sich der Wert »2«, denn da der Wert des ersten Ausdrucks der Wert »0« ist und dieser Wert nicht ungleich Null ist, ist der Wert des gesamten Ausdrucks der Wert des Operanden rechts vom Doppelpunkt »:«, also »2«.
main.c
#include <stdio.h>
int main( void )
{ printf( "%d\n", 3 ? 4 : 5 );
printf( "%d\n", 0 ? 1 : 2 ); }stdout
4
2
Bezeichnungen für Teilausdrücke
Wir nennen die drei Operanden des ternären Ausdrucks entsprechend ihrer Bedeutung auch Bedingung, Konsequenz und Alternative .
- Der ternäre Ausdruck
.-----------. .-. .------------. .-. .-------------.
--->| Bedingung |--->( ? )--->| Konsequenz |--->( : )--->| Alternative |--->
'-----------' '-' '------------' '-' '-------------'
Die Konsequenz und die Alternative werden zusammen auch als Zweige des ternären Ausdrucks bezeichnet.
Wahrheitswerte und Wahrheitskontexte
Falls sich ein Ausdruck an einer Stelle eines Programms befindet, in der es nur darum geht, ob der Ausdruck ungleich Null ist, so wird diese Stelle auch als ein Wahrheitskontext bezeichnet. Der erste Operand des ternären Operators befindet sich beispielsweise in einem Wahrheitskontext.
Man kann Werte ungleich Null in einem Wahrheitskontext als eine Repräsentation des Wahrheitswertes „wahr“ ansehen, und den Wert Null als eine Darstellung des Wahrheitswertes „falsch“. Wenn man einen Zahlenwert auf diese Weise interpretiert, so nennt man ihn auch einen Wahrheitswert.
Wir sagen auch, daß eine Bedingung erfüllt sei, wenn sie ungleich Null ist. Mit den neuen Begriffen können die Regeln zur Auswertung eines ternären Ausdrucks etwas anschaulicher formuliert werden:
Auswertung eines ternären Ausdrucks
Bei der Auswertung eines ternären Ausdrucks wird zuerst die Bedingung ausgewertet.
▶ Wenn die Bedingung erfüllt ist, dann wird die Konsequenz ausgewertet, die Alternative wird nicht ausgewertet, und der Wert des gesamten ternären Ausdrucks ist der Wert der Konsequenz,
▶ sonst wird die Alternative Ausdruck ausgewertet, der zweite Ausdruck wird nicht ausgewertet, und der Wert des gesamten ternären Ausdrucks ist der Wert der Alternative.
- Symbolische Darstellung der Verzweigung
.---------------. .-. .-.
--->| Bedingung |--->( ? )--->( : )
'---------------' '-' .'-'.
.' '.
.' '.
.' '.
.' '.
.-------------. .-------------.
| Konsequenz | | Alternative |
'-------------' '-------------'- Symbolische Darstellung der Verzweigung (für eine erfüllte Bedingung)
.---------------. .-. .-.
--->| ungleich Null |--->( ? )--->( : )
'---------------' '-' .'-'
.'
.'
.'
.'
.-------------. .-------------.
| Konsequenz | | Alternative |
'-------------' '-------------'- Symbolische Darstellung der Verzweigung (für eine nicht erfüllte Bedingung)
.---------------. .-. .-.
--->| Null |--->( ? )--->( : )
'---------------' '-' '-'.
'.
'.
'.
'.
.-------------. .-------------.
| Konsequenz | | Alternative |
'-------------' '-------------'
Beispiele
Beispiel Darstellung der Auswertungen
main.c
#include <stdio.h>
int vfalse(){ puts( "false" ); return 0; }
int vtrue(){ puts( "true" ); return 1; }int v2(){ puts( "#2" ); return 2; }
int v3(){ puts( "#3" ); return 3; }
int v4(){ puts( "#4" ); return 4; }
int v5(){ puts( "#5" ); return 5; }int main( void )
{ printf( "%d\n", vfalse() ? v2() : v3() );
printf( "%d\n", vtrue() ? v4() : v5() ); }transcript
false
#3
3
true
#4
4
Beispiel Verhindern der Division durch Null
Das folgende Beispiel zeigt, wie eine Division durch Null zu einer Fehlermeldung führt
main.c
#include <stdio.h>
int tausendfacher_kehrwert( int const i ){ return 1000 / i; }
int main( void )
{ printf( "%d\n", tausendfacher_kehrwert( 2 ));
printf( "%d\n", tausendfacher_kehrwert( 0 )); }- Konsole
- 500
(Fehlermeldung)
Das folgende Beispiel zeigt, wie der ternäre Operator verwendet werden kann, um eine Division durch 0 zu vermeiden.
main.c
#include <stdio.h>
int tausendfacher_kehrwert( int const i ){ return i ? 1000 / i : 0; }
int main( void )
{ printf( "%d\n", tausendfacher_kehrwert( 2 ));
printf( "%d\n", tausendfacher_kehrwert( 0 )); }stdout
500
0
Es ist nicht immer sinnvoll, wie oben, als Ergebnis für eine Division durch 0 die Zahl 0 festzulegen. Ob dies in einem bestimmten Fall sinnvoll ist, muß von Fall zu Fall entschieden werden.
Beispiel Verwendung mit Texten
Das folgende Beispiel zeigt, wie Texte als Operanden des ternären Operators verwendet werden können.
Dies erlaubt es uns erstmals, Zahlen in willkürliche Texte umzuwandeln.
main.c
#include <stdio.h>
char * deutsch( int const i ){ return i ? "Eins" : "Null"; }
int main( void )
{ puts( deutsch( 0 ));
puts( deutsch( 1 )); }stdout
Null
Eins
Beispiel Verwendung mit Arithmetik
main.c
#include <stdio.h>
/** @brief Gibt aus, ob zwei int-Werte gleich sind.
@param x ein beliebiger int-Wert
@param y ein beliebiger int-Wert */void pruefe_gleichheit( int const x, int const y )
{ printf
( "%d ist %sgleich %d.\n",
x,
y - x ? "nicht " : "",
y ); }int main( void )
{ int x = 2;
int y = 3;
int z = 2;
pruefe_gleichheit( x, y );
pruefe_gleichheit( x, z ); }stdout
2 ist nicht gleich 3.
2 ist gleich 2.
Beispiel Darstellung mathematischer Terme
In der Mathematik werden Funktionen machmal in einer Schreibweise mit einer großen geschweiften Klammer definiert. (Im folgenden soll „|=“ die Bedeutung „ungleich“ haben.)
- Mathematische Schreibweise
.-
|
| 4 , falls x |= 0,
f( x ):= <
| 2 sonst.
|
'-
In der Mathematik soll diese Schreibweise bedeuten, daß der Wert des Terms »f( x )« gleich »4« ist, wenn x ungleich Null ist, und gleich »3« sonst.
Mit Hilfe des ternären Ausdrucks kann diese mathematische Schreibweise nun relativ direkt in C dargestellt werden.
- C -Schreibweise
double f( double const x ){ return x ? 4 : 2; }
Beispiel Verwendung mit Prädikaten
Das folgende Programmbeispiel zeigt eine Verwendung des ternären Operators mit einem Prädikat. Ein Prädikat ist eine deterministische Funktion, deren Aufruf als Aussage interpretiert wird. Der Aufruf »isalpha( c )« ist beispielsweise die Aussage, daß die Kennzahl »c« zu einem Buchstaben gehört.
Die Auswertung einer Aussage soll einen Wert ungleich Null ergeben, wenn die Aussage wahr ist, und Null sonst. Die Werte von Aussagen werden also als Wahrheitswerte interpretiert.
Prädikate und die erste Operandenstelle des ternären Operators sind wie für einander gemacht, denn ein Prädikat ergibt einen Wahrheitswert und die erste Operandenstelle des ternären Operators bildet einen Wahrheitskontext.
Das Prädikat »isalpha« ergibt, ob eine Kennzahl zu einem Buchstaben gehört, indem es nur dann einen Wert ungleich Null zurückgibt. Das folgende Programm stellt diese Information in deutscher Sprache dar.
main.c
#include <stdio.h>
#include <ctype.h>void check( int const c )
{ printf
( "Das Zeichen '%c' ist %sein Buchstabe.\n",
c, isalpha( c )? "" : "k" ); }int main( void )
{ check( 64 );
check( 65 ); }stdout
Das Zeichen '@' ist kein Buchstabe.
Das Zeichen 'A' ist ein Buchstabe.
Beispiel Verschachtelung ternärer Operatoren
Das folgende Beispiel zeigt, wie zwei ternäre Operatoren ineinander verschachtelt werden können.
Wir nehmen an, daß die Funktion »deutsch« nur für ein Argument mit Werten aus der Menge {0, 1, 2} gedacht ist.
main.c
#include <stdio.h>
char * deutsch( int const i )
{ return i ? i - 1 ? "Zwei" : "Eins" : "Null"; }int main( void )
{ puts( deutsch( 0 ));
puts( deutsch( 1 ));
puts( deutsch( 2 )); }stdout
Null
Eins
Zwei
Das folgende Programm zeigt eine Darstellung der Interpretation der obigen Verschachtelung mit Hilfe runder Klammern.
main.c
#include <stdio.h>
char * deutsch( int const i )
{ return i ?( i - 1 ? "Zwei" : "Eins" ): "Null"; }int main( void )
{ puts( deutsch( 0 ));
puts( deutsch( 1 ));
puts( deutsch( 2 )); }stdout
Null
Eins
Zwei
Das folgende Programm zeigt eine Darstellung der Interpretation des Ausdrucks »i ? i - 1 ? "Zwei" : "Eins" : "Null"« mit Hilfe von Funktionsaufrufen.
main.c
#include <stdio.h>
char * positiv( int const i )
{ return i - 1 ? "Zwei" : "Eins"; }char * deutsch( int const i )
{ return i ? positiv( i ): "Null"; }int main( void )
{ puts( deutsch( 0 ));
puts( deutsch( 1 ));
puts( deutsch( 2 )); }stdout
Null
Eins
Zwei
Übungsfragen
? Werte von Ausdrücken
Welchen Wert hat der Ausdruck »1 ? 3 : 4«?
Welchen Wert hat der Ausdruck »0 ? 12.2 : 9.1«?
Welchen Wert hat der Ausdruck »2 ? 3 : 4«?
Welchen Wert hat der Ausdruck »-12 ? "alpha" : "gamma"«?
Welchen Wert hat der Ausdruck »2 ? 0 ? 12.2 : 9.1 : 4«?
? Gattung von Quelltexten
Welche der folgenden beiden Zeilen ist eine Anweisung?
putchar( 65 )
{}
Übungsaufgaben
/ Eine Wirkfunktion
Schreiben Sie eine Funktion »put_deutsch«, die für den Argumentwert »0« den Text »Null«, für den Argumentwert »1« den Text »Eins« und für den Argumentwert »2« den Text »Zwei« ausgibt. Verwenden Sie dabei die folgende Definition der Funktion »deutsch«, ohne diese Definition zu verändern. („Verwenden“ bedeutet so viel wie, die untenstehende Definition der Funktion »deutsch« zu kopieren und die Funktion »deutsch« dann aufzurufen.)
- Die Definition der Funktion »deutsch«
char * deutsch( int const i )
{ return i ? i - 1 ? "Zwei" : "Eins" : "Null"; }
/ Eine Wirkfunktion (1)
Schreiben Sie eine Funktion »putl_deutsch«, die für den Argumentwert »0« die Zeile »Null«, für den Argumentwert »1« die Zeile »Eins« und für den Argumentwert »2« die Zeile »Zwei« ausgibt. Der Unterschied zur Funktion »put_deutsch« aus der vorigen Aufgabe besteht darin, daß dem ausgegebenen Wort nun ein Zeilenende folgen soll. Verwenden Sie in Ihrer Lösung die in der vorigen Übungsaufgabe geschriebene Definition der Funktion »put_deutsch«, ohne diese Definition zu verändern.
/ Eine willkürliche Funktion
Schreiben Sie eine Funktion, die 17 ergibt, falls ihr Argumentwert gleich 4 ist, und 12, falls ihr Argumentwert gleich 6 ist. Verwenden Sie dazu den ternären Operator.
/ Eine willkürliche Funktion (1)
Schreiben Sie eine Funktion, die den Text »alpha« für den Argumentwert 0 und den Text »gamma« für den Argumentwert 1 ergibt. Verwenden Sie dazu den ternären Operator.
/ Eine willkürliche Funktion (2)
Schreiben Sie eine Funktion, die den Text »alpha« für den Argumentwert 0, den Text »gamma« für den Argumentwert 1 und den Text »delta« für den Argumentwert 2 ergibt. Verwenden Sie dazu den ternären Operator.
/ Eine willkürliche Funktion (3)
Schreiben Sie eine Funktion, die den Text »3 Punkte« ausgibt, wenn sie mit einem Argumentwert von »3« aufgerufen wird; »2 Punkte«, wenn sie mit einem Argumentwert von »2« aufgerufen wird; »1 Punkt«, wenn sie mit einem Argumentwert von »1« aufgerufen wird; und »0 Punkte«, wenn sie mit einem Argumentwert von »0« aufgerufen wird
/ Normalisierung
Wir sagen, daß eine Funktion »f« einen Wert »x« „auf einen Wert »y« abbildet“, wenn die Funktion deterministisch ist und der Wert des Ausdrucks »f( v )« gleich »y« ist, wann immer der Wert des Ausdrucks »v« gleich »x« ist. Beispielsweise bildet die Funktion »sqrt« den Wert‑»4« auf den Wert‑»2« ab.
Definieren Sie eine Funktion, welche den Wert »0« auf den Wert »0« und alle anderen Werte auf den Wert »1« abbildet.
/ Verneinung
Definieren Sie eine Funktion, welche den Wert »0« auf den Wert »1« und alle anderen Werte auf den Wert »0« abbildet.
/ Und-Verknüpfung
Definieren Sie eine Funktion, die den Wert »1« ergibt, wenn beide Argumente ungleich Null sind, und den Wert »0« sonst.
/ Oder-Verknüpfung
Definieren Sie eine Funktion, die den Wert »0« ergibt, wenn beide Argumente gleich Null sind, und den Wert »1« sonst.
/ Exklusive oder-Verknüpfung
Definieren Sie eine Funktion, die den Wert »1« ergibt, wenn beide Argumente einander ungleich sind, und den Wert »0« sonst. Hierfür kann angenommen werden, daß als Argumentwerte nur der Wert »0« und der Wert »1« vorkommen.
/ Gleichheit
Definieren Sie eine Funktion, die den Wert »1« ergibt, wenn beide Argumente einander gleich sind, und den Wert »0« sonst. Hierfür kann angenommen werden, daß als Argumentwerte nur der Wert »0« und der Wert »1« vorkommen.
Zusatzanforderung: Schreiben Sie die Funktion so, daß sie auch für alle anderen Werte (deren Betrag kleiner als »10000« ist) das richtige Ergebnis liefert.
/ Negativ *
Definieren Sie eine Funktion, die den Wert »1« ergibt, wenn ihr Argument negativ ist (ohne bisher noch nicht behandelte Operatoren zu verwenden). (Es ist nicht sicher, ob das möglich ist.)
/ Kleiner *
Definieren Sie eine Funktion, die den Wert »1« ergibt, wenn das erste Argument kleiner ist als das zweite (ohne bisher noch nicht behandelte Operatoren zu verwenden). (Es ist nicht sicher, ob das möglich ist.)