Ein Ausdruck ist in einer Programmiersprache - vereinfacht gesagt - etwas, das einen Wert zurück gibt. Das kann man ganz weit auseinander pflücken, aber wir beschränken uns zunächst darauf, dass ein Ausdruck alles ist, was einen Wert besitzt. Zum Beispiel die Zahl 1
- sie besitzt überraschenderweise den Wert 1 und deswegen ist sie ein Ausdruck. Auch negative Zahlen sind möglich und besitzen einen Wert: Zum Beispiel -1
.
Wie schon gesagt, für einen Computer existieren im Prinzip nur Zahlen. Auch Buchstaben sind im Prinzip nur Zahlen. Welcher Zahlenwert für welches Zeichen verantwortlich ist, kann man in der ASCII-Tabelle nachschlagen. Zeichen werden in C mit einfachen Anführungszeichen geschrieben, zum Beispiel '1'
. Vielleicht kommt nun überraschend, dass '1'
den Wert 49 hat, aber das lässt sich in der ASCII-Tabelle so nachschlagen. Es ist wirklich so. Für dieses Kapitel ist nur wichtig, dass auch '1'
einen Wert besitzt und damit ein Ausdruck ist.
Auch Zeichenketten, wie „Hello proggen.org“
sind letztendlich nur Zahlen. Wie Zeichenketten vom C-Compiler gehandhabt werden, erfahren wir später. Aber auch hier gilt: Am Schluss kommt eine Zahl heraus und damit ist das ein Ausdruck.
Wir haben aber auch bereits Konstrukte kennen gelernt, die keine Ausdrücke sind. #include
liefert keinen Wert zurück, die Deklaration der Funktion main
liefert keinen Wert zurück und auch return 0;
liefert keinen Wert zurück, den man einer Variablen zuweisen könnte, sondern beendet eine Funktion. Anders der Funktionsaufruf der Funktion main
: Beim Aufruf der Funktion erhält man einen Ganzzahl (int) zurück. printf() könnte als Funktion einen Wert zurückliefern (tut dies auch, wir ignorieren ihn bisher nur), aber darauf gehen wir später ein. Ein Funktionsaufruf kann also ein Ausdruck sein, sofern er etwas zurück liefert. „Funktionen“, die void
zurückgeben, nennt man Prozeduren, weil sie - im Unterschied zu Funktionen - eben nichts zurück geben. Prozeduren sind entsprechend kein Ausdruck.
Mit Hilfe von Operatoren kann man Werte miteinander verknüpfen. Hier gibt es natürlich die grundlegenden Rechenarten, wie Addition (+
), Subtraktion (-
), Multiplikation (*
) und Division (/
).
Folgendes sind entsprechend gültige Ausdrücke:
17 + 4 18 - 10 21 * 3 10 / 4
Auch gebrochene Zahlen lassen sich ausdrücken, allerdings werden sie nach amerikanischem Stil mit einem Punkt statt mit einem Komma geschrieben. Führende Nullen bzw. nachfolgende Nullen müssen nicht geschrieben werden. Der Punkt hingegen unterscheidet hier aber zwischen reellen und natürliche Zahlen, da ein Computer hier unterschiedlich rechnet.
1.7 + 0.4 1.8 - 1.0 2.1 * .3 1. / 0.4
Schreibt man einen Ausdruck wie
1 + 2.5
so führen moderne Compiler allerdings die korrekte Rechenart aus, in der die natürliche Zahl 1
als eine reelle Zahl 1.0
verstanden wird.
Da alles Zahlen sind, kann man in C auch Zeichen miteinander verrechnen:
'1' - '0'
Das ergibt dann 1, weil '1'
ist 49 und '0'
ist 48: 49-48 ist 1. So lässt sich der Wert eines Ziffernzeichens leicht bestimmen, wenn man den ASCII-Wert des Ziffernzeichens '0' abzieht.
Der Ausdruck 17 + 4
besitzt den Wert 21. Damit ist 17 + 4
ein Ausdruck und kann wieder mit Hilfe von Operatoren verknüpft werden, zum Beispiel so:
17 + 4 * 3
Hier kommt durch die Auswertung des Ausdrucks der Wert 29 heraus. Ja, auch C beachtet Punkt vor Strichrechnung! Die einzelnen Operatoren haben eine festgelegte Reihenfolge, wie sie ausgeführt werden. Hierfür haben wir eine Tabelle angefertigt, die die Priorität für alle Operatoren auflistet. Ist die Priorität höher, dann wird der jeweilige Operator bevorzugt behandelt. Die höchste Priorität besitzt die Klammerung: Hiermit kann man sich - wie in der Mathematik - über die festgelegten Operatorenprioritäten hinwegsetzen:
(17 + 4) * 3
und erhält so den Wert 63.
Ein Ausdruck ist die Repräsentation eines Wertes, wie die 1
den Wert 1 repräsentiert. Aber auch 3-2
ist ein Ausdruck, der den Wert 1 repräsentiert. Ein Ausdruck ergibt nach seiner Auswertung immer einen Wert.
Bisher haben wir uns mit dem Wert von konkreten Ausdrücken beschäftigt. Jetzt gehen wir einen Schritt zurück und betrachten den Datentyp. Wir haben ja schon gesehen, dass zwischen ganzen und reellen Zahlen unterschieden wird.
Der Ausdruck 1
ist eine ganze Zahl. Ganze Zahlen sind abzählbar, auf Englisch integer. Der Datentyp heißt Int
, wie wir ihn schon als Rückgabewert der Funktion main()
kennen: Die Funktion gibt einen Wert zurück, der eine zählbare Zahl darstellt - aber welcher Wert ist nicht festgelegt. Das entscheidet sich erst, wenn die Funktion ausgeführt wird.
Reelle Zahlen besitzen einen anderen Datentyp, er nennt sich float
oder double
. In C haben reelle Zahlen standardmäßig den Typ double
, was in diesem Fall für doppelte Breite steht und zu einer höheren Genauigkeit der Zahlen führt. Es gibt jedoch einen weiteren Typ für reelle Zahlen mit einfacher Breite, also geringerer Genauigkeit. Dieser Typ nennt sich float
und kann durch ein folgendes f
nach der reellen Zahl angegeben werden.
5.7f + 1.23f
Als Eselsbrücke für den Typ float
kann man sich zunächst vorstellen, dass integer Zahlen stufenweise nach oben gehen, während reelle Zahlen eher fließend ineinander übergehen.
Reelle Zahlen können unendlich breit sein (z.B. Pi hat unendlich viele Ziffern), man kann aber in einer Fließkommazahl nur eine begrenzte Menge Stellen speichern.
Du solltest nun Werte von Ausdrücken unterscheiden können und verstanden haben, dass Werte - unabhängig davon, ob sie über ausgewertete Ausdrücke entstanden sind oder direkt als Wert im Quelltext stehen - einen Datentyp haben.
Bisher kennen wir die Datentypen Int, float und double und wissen, dass Integerwerte als Zahl ohne Komma (bzw. besser gesagt ohne einem Punkt) dargestellt werden, Doubles mit einem Punkt und Floats mit einem Punkt sowie einem folgenden f
.
Weiterhin haben wir die grundlegenden Rechenoperationen gesehen, so dass wir uns in der nächsten Lektion mit einfachen Aufgaben beschäftigen können.