C-Programme bestehen aus Anweisungen, und die meisten Anweisungen setzen sich aus Ausdrücken und Operatoren zusammen. Deshalb benötigen Sie zum Schreiben eines C-Programms eine gute Kenntnis von Anweisungen, Ausdrücken und Operatoren. Heute lernen Sie:
if
-Anweisung kennen
Eine Anweisung ist ein vollständiger Befehl, der den Computer dazu anhält, eine
bestimmte Aufgabe auszuführen. Normalerweise nehmen Anweisungen in C eine
ganze Zeile ein. Es gibt jedoch auch einige Anweisungen, die sich über mehrere Zeilen
erstrecken. C-Anweisungen werden immer mit einem Semikolon abgeschlossen (eine
Ausnahme dazu bilden die Präprozessor-Direktiven #define
und #include
, die wir am
Tag 20, »Compiler für Fortgeschrittene«, noch eingehender untersuchen werden).
Einige C-Anweisungen haben Sie bereits kennen gelernt. So ist zum Beispiel
x = 2 + 3;
eine Zuweisung. Sie weist den Computer an, die Werte 3 und 2 zu addieren und das
Ergebnis der Variablen x
zuzuweisen. Im Laufe dieses Buches werden ich Ihnen noch
weitere Formen von Anweisungen vorstellen.
Der Begriff Whitespace bezieht sich auf Leerzeichen, Tabulatoren und leere Zeilen in Ihrem Quelltext. Dieser Whitespace wird vom C-Compiler nicht berücksichtigt. Konkret bedeutet dies, dass Ihr Compiler, wenn er eine Anweisung in Ihrem Quelltext liest, Ausschau nach den Zeichen in der Anweisung und dem abschließenden Semikolon hält und Whitespace ignoriert. Demzufolge ist die Anweisung
x=2+3;
x = 2 + 3;
x =
2
+
3 ;
Dadurch sind Sie sehr flexibel, was die Formatierung Ihres Quellcodes angeht. Sie sollten jedoch von einer Formatierung wie im letzten Beispiel absehen. Anweisungen sollten immer jeweils eine Zeile einnehmen und links und rechts von Variablen und Operatoren die gleichen Abstände aufweisen. Wenn Sie sich an die Formatierungs- konventionen dieses Buches halten, können Sie nichts falsch machen. Mit zunehmender Erfahrung werden Sie vielleicht feststellen, dass Sie einiges doch lieber anders schreiben würden, aber das Hauptziel sollte immer ein lesbarer Quellcode sein.
Die Regel, dass C Whitespace ignoriert, hat natürlich auch eine Ausnahme. Innerhalb von literalen Stringkonstanten werden Tabulatoren und Leerzeichen nicht ignoriert, sondern als Teil des Strings interpretiert. Ein String ist eine Folge von Zeichen. Literale Stringkonstanten sind Strings, die in Anführungszeichen stehen und (Leer- )Zeichen für (Leer-)Zeichen vom Compiler gelesen werden. Ein Beispiel für einen literalen String ist
"Wadde hadde dudde da"
Dieser literale String unterscheidet sich von:
"Wadde hadde dudde da"
Der Unterschied liegt in den zusätzlichen Leerzeichen. In literalen Strings werden Whitespace-Zeichen berücksichtigt.
Der folgende Code ist zwar extrem schlechter Stil, aber völlig legal in C:
printf(
"Hallo, Welt!"
);
Das folgende Beispiel wird zwar vom GNU-C-Compiler zugelassen, entspricht aber nicht den Standardregeln für C. Das bedeutet, dass Sie solchen Code vermeiden sollten, auch wenn der gcc keine Fehlermeldung ausgibt. Andernfalls könnten Sie Schwierigkeiten bekommen, wenn Sie versuchen, Ihren Code mit einem anderen C-Compiler zu kompilieren.
printf("Hallo,
Welt!");
Um eine literale Stringkonstante zu umbrechen, müssen Sie direkt vor dem Umbruch
das Backslash-Zeichen (\
) einfügen. Folgendes Beispiel ist demnach zulässig und kann
mit allen ANSI-C-Compilern kompiliert werden.
printf("Hallo,\
Welt!");
Wenn Sie ein vereinzeltes Semikolon allein in eine Zeile setzen, erzeugen Sie eine so genannte Leeranweisung - eine Anweisung, die keine Aufgabe ausführt. Dies ist in C absolut zulässig. Weiter hinten in diesem Buch werden Sie erfahren, in welcher Hinsicht Leeranweisungen nützlich sein können.
Eine Verbundanweisung, auch Block genannt, ist eine Gruppe von zwei oder mehr C-Anweisungen, die in geschweiften Klammern steht. Sehen Sie dazu folgendes Beispiel für einen Block:
{
printf("Hallo, ");
printf("Welt!");
}
In C kann ein Block überall dort verwendet werden, wo auch eine einfache Anweisung eingesetzt werden kann. Sie werden in diesem Buch viele Beispiele dafür finden. Beachten Sie, dass die Stellung der geschweiften Klammern auch eine andere sein kann. Folgender Code ist demnach zum obigen Beispiel äquivalent:
{printf("Hallo, ");
printf("Welt!");}
Es ist ratsam, geschweifte Klammern jeweils allein in eigene Zeilen zu schreiben und damit den Anfang und das Ende eines Blocks deutlich sichtbar zu machen. Außerdem können Sie auf diese Art und Weise schneller feststellen, ob Sie eine Klammer vergessen haben.
In C versteht man unter einem Ausdruck alles, was einen numerischen Wert zum Ergebnis hat. C-Ausdrücke können einfach oder sehr komplex sein.
Der einfachste C-Ausdruck besteht aus einem einzigen Element: einer einfachen Variablen, einer literalen Konstante oder einer symbolischen Konstante. Hier einige Beispiele für Ausdrücke:
Eine literale Konstante wird zu ihrem Wert ausgewertet. Eine symbolische
Konstante wird zu dem Wert ausgewertet, der ihr bei ihrer Erzeugung mit der
#define
-Direktive zugewiesen wurde. Der Wert einer Variablen ist der aktuell durch
das Programm zugewiesene Wert.
Komplexe Ausdrücke sind im Grunde genommen nur einfache Ausdrücke, die durch Operatoren verbunden sind. So ist zum Beispiel
2 + 8
ein Ausdruck, der aus den zwei Unterausdrücken 2
und 8
und dem Additionsoperator
+
besteht. Der Ausdruck 2 + 8
wird, wie Sie wissen, zu 10
ausgewertet. Sie können in
C auch sehr komplexe Ausdrücke schreiben:
1.25 / 8 + 5 * rate + rate * rate / kosten
Wenn ein Ausdruck mehrere Operatoren enthält, wird die Auswertung des Ausdrucks von der Rangfolge der Operatoren bestimmt. Die Rangfolge der Operatoren sowie Einzelheiten zu den Operatoren in C selbst werden später in diesem Kapitel noch besprochen.
C-Ausdrücke können sogar noch interessanter sein. Betrachten Sie einmal folgende Zuweisung:
x = a + 10;
Diese Anweisung wertet den Ausdruck a + 10
aus und weist das Ergebnis x
zu.
Darüber hinaus ist die ganze Anweisung x = a + 10
als solche ein Ausdruck, der zu
dem Wert der Variablen links des Gleichheitszeichens ausgewertet wird. Sie sehen in
Abbildung 3.1 eine bildhafte Darstellung.
Abbildung 3.1: Eine Zuweisung ist als solche auch ein Ausdruck.
Deshalb können Sie auch folgende Anweisungen schreiben, die den Wert des
Ausdrucks a
+ 10
sowohl der Variablen x
als auch der Variablen y
zuweist:
y = x = a + 10;
Sie können aber auch Anweisungen wie die folgende schreiben:
x = 6 + (y = 4 + 5);
Dieser Anweisung zufolge erhält y
den Wert 9
und x
den Wert 15
. Beachten Sie die
Klammern, die erforderlich sind, damit die Anweisung kompiliert werden kann. Auf
die Klammern wird weiter hinten im Kapitel noch eingegangen.
Ein Operator ist ein Symbol, das C anweist, eine Operation oder Aktion auf einem oder mehreren Operanden auszuführen. Ein Operand ist das, was vom Operator verarbeitet wird. In C sind alle Operanden Ausdrücke. Die C-Operatoren lassen sich in mehrere Kategorien aufteilen:
Der Zuweisungsoperator ist das Gleichheitszeichen (=
). Seine Verwendung in der
Programmierung unterscheidet sich von der, die Ihnen aus der normalen Mathematik
her bekannt ist. Wenn Sie in einem C-Programm
x = y;
schreiben, ist damit nicht »x
ist gleich y
« gemeint. Hier bedeutet das
Gleichheitszeichen: »Weise den Wert von y
der Variablen x
zu.« In einer C-Zuweisung
kann die rechte Seite ein beliebiger Ausdruck sein, die linke Seite muss jedoch ein
Variablenname sein. Die korrekte Syntax lautet demzufolge:
variable = ausdruck;
Bei der Ausführung wird ausdruck
ausgewertet und der daraus resultierende Wert wird
variable
zugewiesen.
Die mathematischen Operatoren in C führen mathematische Operationen wie Addition und Subtraktion aus. C verfügt über zwei unäre und fünf binäre mathematische Operatoren.
Die unären mathematischen Operatoren leiten ihren Namen von der Tatsache her, dass sie nur einen Operanden benötigen. In C gibt es zwei unäre mathematische Operatoren, die in Tabelle 3.1 aufgelistet sind.
Die Inkrement- und Dekrementoperatoren können nur mit Variablen und nicht mit Konstanten verwendet werden. Bei der Operation wird der Operand um eins erhöht beziehungsweise erniedrigt. Mit anderen Worten, die Anweisungen
++x;
--y;
x = x + 1;
y = y - 1;
Sie sollten der Tabelle 3.1 bereits entnommen haben, dass beide unären Operatoren sowohl vor dem Operand (Präfix-Modus) als auch nach dem Operand (Postfix- Modus) gesetzt werden können. Diese beiden Modi sind nicht identisch. Der Unterschied liegt im Zeitpunkt der Inkrementierung beziehungsweise Dekrementierung:
Lassen Sie uns dies anhand eines Beispiels veranschaulichen. Betrachten wir die beiden folgenden Anweisungen:
x = 10;
y = x++;
Nach Ausführung dieser Anweisungen hat x
den Wert 11
und y
den Wert 10
. Der Wert
von x
wurde erst y
zugewiesen und dann inkrementiert. Im Gegensatz dazu führen die
folgenden Anweisungen dazu, dass y
und x
beide den Wert 11
haben, da x
zuerst
inkrementiert und erst dann y
zugewiesen wird.
x = 10;
y = ++x;
Denken Sie daran, dass =
der Zuweisungsoperator ist und keine »ist-gleich«-
Anweisung. Als Gedächtnisstütze können Sie sich das =
-Zeichen als »Fotokopier«-
Operator vorstellen. Die Anweisung y = x
bedeutet: »Kopiere x
nach y.
«
Nachfolgende Änderungen an x
- nachdem die Kopie erstellt wurde - haben keine
Auswirkungen mehr auf y
.
Das Programm in Listing 3.1 veranschaulicht den Unterschied zwischen dem Präfix- und dem Postfix-Modus.
Listing 3.1: Der Präfix- und der Postfix-Modus.
1: /* Der Präfix- und der Postfix-Modus bei unären Operatoren */
2:
3: #include <stdio.h>
4:
5: int a, b;
6:
7: int main(void)
8: {
9: /* Setzt a und b gleich 5 */
10:
11: a = b = 5;
12:
13: /* Beide werden mehrfach ausgegeben und jedes Mal dekrementiert. */
14: /* Für b wird der Präfix-Modus verwendet, für a der Postfix-Modus */
15:
16: printf("\nPost Prae");
17: printf("\n%d %d", a--, --b);
18: printf("\n%d %d", a--, --b);
19: printf("\n%d %d", a--, --b);
20: printf("\n%d %d", a--, --b);
21: printf("\n%d %d\n", a--, --b);
22:
23: return 0;
24: }
Post Prae
5 4
4 3
3 2
2 1
1 0
Dieses Programm deklariert in Zeile 5 zwei Variablen, a
und b
. In Zeile 11 werden die
Variablen auf den Wert 5
gesetzt. Im Zuge der Ausführung der einzelnen printf()
-
Anweisungen (Zeilen 17 bis 21) werden a
und b
jeweils um eins dekrementiert. a
wird
erst ausgegeben und dann dekrementiert, während b
erst dekrementiert und dann
ausgegeben wird.
Die binären mathematischen Operatoren in C benötigen zwei Operanden. Eine Übersicht über die binären Operatoren, mit denen die allgemeinen Taschenrechner- Kalkulationen durchgeführt werden können, finden Sie in Tabelle 3.2.
Gibt den Rest an, der bleibt, wenn der erste Operand durch den zweiten Operanden dividiert wurde |
Tabelle 3.2: Binäre mathematische Operatoren in C.
Die ersten vier Operatoren der Tabelle 3.2 sollten Sie eigentlich kennen, so dass Sie ohne Schwierigkeiten damit rechnen können. Der fünfte Operator, Modulus, ist vielleicht nicht ganz so bekannt. Er liefert den Rest einer Division zurück. So ist zum Beispiel 11 Modulus 4 gleich 3 (das heißt 11 geteilt durch 4 ist gleich 2 mit dem Rest 3). Sehen Sie dazu im Folgenden noch einige weitere Beispiele:
100 modulus 9 gleich 1
10 modulus 5 gleich 0
40 modulus 6 gleich 4
Listing 3.2 zeigt Ihnen, wie Sie mit dem Modulus-Operator eine große Sekundenzahl in Stunden, Minuten und Sekunden umwandeln können.
Listing 3.2: Beispiel für den Modulus-Operator.
1: /* Beispiel für den Modulus-Operator. */
2: /* Liest eine Sekundenzahl ein und konvertiert diese */
3: /* in Stunden, Minuten und Sekunden. */
4:
5: #include <stdio.h>
6:
7: /* Definition von Konstanten */
8:
9: #define SEK_PRO_MIN 60
10: #define SEK_PRO_STD 3600
11:
12: unsigned sekunden, minuten, stunden, sek_rest, min_rest;
13:
14: int main(void)
15: {
16: /* Eingabe der Sekundenzahl */
17:
18: printf("Geben Sie eine Anzahl an Sekunden ein : ");
19: scanf("%d", &sekunden);
20:
21: stunden = sekunden / SEK_PRO_STD;
22: minuten = sekunden / SEK_PRO_MIN;
23: min_rest = minuten % SEK_PRO_MIN;
24: sek_rest = sekunden % SEK_PRO_MIN;
25:
26: printf("%u Sekunden entsprechen ", sekunden);
27: printf("%u h, %u m und %u s\n", stunden, min_rest, sek_rest);
28:
29: return 0;
30: }
Geben Sie eine Anzahl an Sekunden ein : 60
60 Sekunden entsprechen 0 h, 1 m, and 0 s
Geben Sie eine Anzahl an Sekunden ein : 10000
10000 Sekunden entsprechen 2 h, 46 m, and 40 s
Das Programm in Listing 3.2 hat den gleichen Aufbau wie alle vorigen Programme.
Die Zeilen 1 bis 3 teilen Ihnen anhand eines Kommentars mit, was das Programm
macht. Zeile 4 ist reiner Whitespace, um das Programm lesbarer zu machen. Ebenso
wie Whitespace-Zeichen in Anweisungen und Ausdrücken werden auch Leerzeilen
vom Compiler ignoriert. Zeile 5 bindet die für dieses Programm notwendige Header-
Datei ein. Die Zeilen 9 und 10 definieren zwei Konstanten, SEK_PRO_MIN
und
SEK_PRO_STD
, die Ihnen das Lesen der Anweisungen im Programm erleichtern sollen.
Zeile 12 deklariert alle benötigten Variablen. Manche Programmierer ziehen es vor,
jede Variable auf einer eigenen Zeile zu deklarieren, anstatt sie alle in eine Zeile zu
setzen. Doch dies ist, wie vieles in C, nur eine Frage des Stils. Beide Methoden sind
erlaubt.
In Zeile 14 steht die Funktion main()
, die den Hauptteil des Programms enthält. Um
Sekunden in Stunden und Minuten umzurechnen, muss das Programm zuerst die
Werte mitgeteilt bekommen, mit denen es arbeiten soll. Dazu wird in Zeile 18 mit
Hilfe der printf()
-Funktion eine Eingabeaufforderung auf dem Bildschirm
ausgegeben. In der nachfolgenden Zeile wird die eingegebene Zahl mit Hilfe der
scanf()
-Funktion eingelesen. Die scanf()
-Anweisung speichert die umzuwandelnde
Anzahl der Sekunden in der Variablen sekunden
. Mehr zu den Funktionen scanf()
und
printf()
erfahren Sie am Tag 6, »Grundlagen der Ein- und Ausgabe«. Zeile 21 enthält
einen Ausdruck, der die Zahl der Stunden ermittelt (durch Teilen der Anzahl der
Sekunden durch die Konstante SEK_PRO_STD
). Da stunden
eine Integer-Variable ist,
wird der Restwert ignoriert. Zeile 22 verwendet die gleiche Logik, um die Gesamtzahl
der Minuten für die eingegebene Sekundenzahl festzustellen. Da die in Zeile 22
errechnete Gesamtzahl der Minuten auch die Minuten für die Stunden enthält,
verwendet Zeile 23 den Modulus-Operator, um die Gesamtzahl der Minuten durch die
Anzahl an Minuten pro Stunde (entspricht dem Wert von SEK_PRO_MIN
) zu teilen und
die restlichen Minuten zu erhalten. Zeile 24 führt eine ähnliche Berechnung zur
Ermittlung der übrig gebliebenen Sekunden durch. Die Zeilen 26 und 27 dürften
Ihnen inzwischen schon bekannt vorkommen, sie übernehmen die in den Ausdrücken
errechneten Werte und geben sie aus. Zeile 29 beendet das Programm mit dem
Zurückgeben von 0
an das Betriebssystem.
Wenn ein Ausdruck mehr als einen Operator enthält, stellt sich die Frage, in welcher Reihenfolge die Operationen ausgeführt werden. Wie wichtig diese Frage ist, zeigt die folgende Zuweisung:
x = 4 + 5 * 3;
Wenn zuerst addiert wird, erhalten Sie als Ergebnis für x
den Wert 27
:
x = 9 * 3;
Wird hingegen zuerst multipliziert, ergibt sich Folgendes, und x
wird der Wert 19
zugewiesen.
x = 4 + 15;
Dies belegt deutlich, dass es fester Regeln bedarf, die die Reihenfolge für die Auswertung der Operationen bestimmen. Diese Reihenfolge, auch Operator- Rangfolge genannt, ist in C streng geregelt. Jeder Operator hat eine bestimmte Priorität. Wenn ein Ausdruck ausgewertet wird, werden die Operatoren mit der höheren Priorität zuerst ausgeführt. Tabelle 3.3 zeigt Ihnen die Rangfolge der mathematischen Operatoren in C. Die Zahl 1 bedeutet höchste Priorität, und Operatoren dieser Priorität werden folglich zuerst ausgeführt.
Ein Blick auf die Tabelle 3.3 zeigt Ihnen, dass in allen C-Ausdrücken für die Ausführung von Operationen die folgende Reihenfolge gilt:
Wenn ein Ausdruck mehr als einen Operator der gleichen Priorität enthält, werden
die Operatoren in der Regel nach ihrem Erscheinen von links nach rechts ausgeführt.
So haben zum Beispiel in dem folgenden Ausdruck die Operatoren %
und *
die gleiche
Priorität, aber %
steht am weitesten links und wird deshalb auch zuerst ausgeführt.
12 % 5 * 2
Die Auswertung dieses Ausdrucks ergibt 4
(12
%
5
ergibt 2
; 2
mal 2
ist 4
).
Doch kehren wir zu dem Beispiel von oben zurück. Nach der hier beschriebenen
Operator-Rangfolge weist die Anweisung x = 4 + 5 * 3;
der Variablen x
den Wert 19
zu, da die Multiplikation vor der Addition erfolgt.
Was aber, wenn Sie bei der Berechnung Ihres Ausdrucks von der Rangfolge der
Operatoren abweichen wollen? Wenn Sie zum Beispiel in unserem obigen Beispiel
erst 4
und 5
addieren und dann die Summe mit 3
multiplizieren wollen? In C können
Sie mit Klammern auf die Auswertung des Ausdrucks beziehungsweise die Operator-
Rangfolge Einfluss nehmen. Ein in Klammern gefasster Unterausdruck wird immer
zuerst ausgewertet, unabhängig von der Rangfolge der Operatoren. So könnten Sie
zum Beispiel schreiben:
x = (4 + 5) * 3;
Der in Klammern gefasste Ausdruck 4 + 5
wird zuerst ausgewertet, so dass x
in
diesem Fall der Wert 27
zugewiesen wird.
Sie können in einem Ausdruck mehrfach ineinander verschachtelte Klammern verwenden. Bei verschachtelten Klammern werden die Klammern immer von innen nach außen ausgewertet. Betrachten wir folgenden komplexen Ausdruck:
x = 25 - (2 * (10 + (8 / 2)));
Dieser Ausdruck wird wie folgt ausgewertet:
8 / 2
, wird zuerst ausgewertet und ergibt den Wert 4
:
25 - (2 * (10 + 4))
10 + 4
ausgewertet,
mit dem Ergebnis 14
:
25 - (2 * 14)
2 * 14
, ausgewertet und ergibt den Wert 28
:
25 - 28
25 - 28
, ausgewertet und
der Variablen x
der Wert -3
zugewiesen:
x = -3
Klammern müssen nicht unbedingt dazu verwendet werden, um Einfluss auf die Operator-Rangfolge zu nehmen. Sie können auch der Verdeutlichung der Bezüge dienen. Klammern müssen immer paarweise auftreten. Andernfalls gibt der Compiler eine Fehlermeldung aus.
Wie bereits im vorherigen Abschnitt erläutert, werden mehrere Operatoren der gleichen Priorität in einem C-Ausdruck immer von links nach rechts ausgewertet. So wird zum Beispiel in dem Ausdruck
w * x / y * z
zuerst w
mit x
multipliziert, das Ergebnis der Multiplikation danach durch y
geteilt und
das Ergebnis der Division dann mit z
multipliziert.
Über alle Prioritätsebenen hinweg gibt es jedoch keine Garantie für eine Ausführung von links nach rechts. Sehen Sie dazu folgendes Beispiel:
w * x / y + z / y
Aufgrund der Priorität werden die Multiplikation und die Division vor der Addition
ausgeführt. In C gibt es jedoch keine Vorgabe, ob der Unterausdruck w * x / y
oder z
/ y
zuerst ausgewertet werden soll. Wenn Ihnen nicht ganz klar ist, warum dies von
Bedeutung sein kann, betrachten Sie einmal folgendes Beispiel:
w * x / ++y + z / y
Wenn der linke Unterausdruck zuerst ausgewertet wird, wird y
bei der Auswertung des
zweiten Ausdrucks inkrementiert. Wird der rechte Ausdruck zuerst ausgewertet, wird y
nicht inkrementiert und das Ergebnis ist ein anderes. Aus diesem Grunde sollten Sie
diese Art von nichteindeutigen Ausdrücken in Ihren Programmen vermeiden.
Gegen Ende der heutigen Lektion werden im Abschnitt »Übersicht der Operator- Rangfolge« die Prioritäten aller C-Operatoren aufgelistet.
Die Vergleichsoperatoren in C dienen dazu, Ausdrücke zu vergleichen. Dabei ergeben
sich Fragen wie »Ist x größer als 100?« oder »Ist y gleich 0?« Ein Ausdruck mit einem
Vergleichsoperator wird mit einem Integer-Wert von 1
oder 0
ausgewertet. Dabei
kann man den Wert 1
als wahr und den Wert 0
als unwahr betrachten. In Tabelle 3.4
sind die sechs Vergleichsoperatoren von C aufgeführt.
Tabelle 3.5 enthält einige Anwendungsbeispiele für Vergleichsoperatoren. Diese Beispiele verwenden literale Konstanten. Das gleiche Prinzip lässt sich aber auch auf Variablen anwenden.
Vergleichende (relationale) Anweisungen werden immer zu
0
oder1
ausgewertet. Jede Integer-Variable, deren Wert ungleich Null ist, wird als wahr betrachtet. Nur Integer-Werte von Null sind unwahr.
Vergleichsoperatoren werden vornehmlich für relationale Ausdrücke in if
- und while
-
Anweisungen verwendet, die Thema von Kapitel 5, »Grundlagen der
Programmsteuerung«, sind. An dieser Stelle möchte ich Sie lediglich mit den
Grundlagen von if
-Anweisungen vertraut machen. Dieses Grundlagenwissen macht
den Einsatz von Vergleichsoperatoren in Programmsteueranweisungen verständlicher.
Für alle, die Sie sich fragen, was eine Programmsteueranweisung überhaupt ist, sei angemerkt, dass Anweisungen in einem C-Programm normalerweise von oben nach unten, das heißt in der Folge ihres Erscheinens in dem Quellcode, ausgeführt werden. Eine Programmsteueranweisung nimmt auf die Reihenfolge der Programmausführung Einfluss. Programmsteueranweisungen können veranlassen, dass bestimmte Anweisungen mehrmals hintereinander oder unter bestimmten Umständen gar nicht ausgeführt werden. Die
if
-Anweisung ist eine dieser Programmsteueranweisungen in C. Weitere Anweisungen dieser Art, wiedo
undwhile
, werden am Tag 5 besprochen.
In ihrer grundlegenden Form wertet die if
-Anweisung einen Ausdruck aus und legt in
Abhängigkeit vom Ergebnis dieser Auswertung fest, wo die Programmausführung
fortzusetzen ist. Eine if
-Anweisung hat folgende Form:
if (Ausdruck)
Anweisung;
Wenn Ausdruck
wahr ist, wird Anweisung
ausgeführt. Ist Ausdruck
hingegen unwahr,
wird Anweisung
nicht ausgeführt. In beiden Fällen verzweigt die Ausführung in den
Code, der auf die if
-Anweisung folgt. Das lässt die Schlussfolgerung zu, dass die
Ausführung von Anweisung
von dem Ergebnis von Ausdruck
abhängt. Beachten Sie,
dass die if
-Anweisung sowohl aus der Zeile if (
Ausdruck
)
als auch aus der Zeile
Anweisung
;
besteht. Diese zwei Zeilen werden nicht als getrennte Anweisungen
betrachtet.
Eine if
-Anweisung kann die Ausführung mehrerer Anweisungen steuern, indem man
einfach eine Verbundanweisung (einen Block) verwendet. Wie ich bereits zu Beginn
dieses Kapitels definiert habe, versteht man unter einem Block eine Gruppe von zwei
oder mehr Anweisungen innerhalb von geschweiften Klammern. Ein Block kann
überall dort eingesetzt werden, wo auch eine einfache Anweisung verwendet werden
kann. So könnten Sie eine if
-Anweisung auch folgendermaßen schreiben:
if (Ausdruck)
{
Anweisung1;
Anweisung2;
/* hier steht weiterer Code */
Anweisungen;
}
Achten Sie darauf, an das Ende einer
if
-Anweisung kein Semikolon zu setzen. Eineif
-Anweisung sollte immer mit der darauf folgenden Bedingung abschließen. Im folgenden Codefragment wirdAnweisung1
stets ausgeführt, unabhängig davon, obx
gleich2
ist oder nicht. Der Grund liegt darin, dass beide Zeilen jeweils separat ausgeführt und nicht als Einheit erkannt werden:
Wenn Sie selbst programmieren, werden Sie bald feststellen, dass if
-Anweisungen
meistens zusammen mit Vergleichsausdrücken verwendet werden, also in der Form:
»Führe die folgende(n) Anweisung(en) nur aus, wenn (engl. if) die nachstehende
Bedingung wahr ist.« Sehen Sie dazu ein Beispiel:
if (x > y)
y = x;
Dieser Code weist y
den Wert von x
nur dann zu, wenn x
größer als y
ist. Ist x
nicht
größer als y
, wird keine Zuweisung vorgenommen. Listing 3.3 verdeutlicht den Einsatz
von if
-Anweisungen.
Listing 3.3: Beispiel für if-Anweisungen.
1: /* Beispiel für if-Anweisungen */
2:
3: #include <stdio.h>
4:
5: int x, y;
6:
7: int main(void)
8: {
9: /* Liest zwei Werte ein, die getestet werden */
10:
11: printf("\nGeben Sie einen Integer-Wert für x ein: ");
12: scanf("%d", &x);
13: printf("\nGeben Sie einen Integer-Wert für y ein: ");
14: scanf("%d", &y);
15:
16: /* Testet die Werte und gibt das Ergebnis aus */
17:
18: if (x == y)
19: printf("x ist gleich y\n");
20:
21: if (x > y)
22: printf("x ist größer als y\n");
23:
24: if (x < y)
25: printf("x ist kleiner als y\n");
26:
27: return 0;
28: }
Geben Sie einen Integer-Wert für x ein: 100
Geben Sie einen Integer-Wert für y ein: 10
x ist größer als y
Geben Sie einen Integer-Wert für x ein: 10
Geben Sie einen Integer-Wert für y ein: 100
x ist kleiner als y
Geben Sie einen Integer-Wert für x ein: 10
Geben Sie einen Integer-Wert für y ein: 10
x ist gleich y
Das Listing enthält drei if
-Anweisungen (Zeile 18 bis 25). Viele Zeilen in diesem
Programm sollten Ihnen vertraut sein. Zeile 5 deklariert die zwei Variablen x
und y
,
und die Zeilen 11 bis 14 fordern den Benutzer auf, Werte für diese Variablen
einzugeben. In den Zeilen 18 bis 25 stehen if
-Anweisungen, mit denen geprüft wird,
ob x
kleiner als, größer als oder gleich y
ist. Beachten Sie Zeile 18, die mit einer if
-
Anweisung feststellt, ob x
gleich y
ist. Dabei möchte ich Sie daran erinnern, dass ==
der Gleichheitsoperator ist und »ist gleich« bedeutet. Sie sollten ihn nicht mit dem
Zuweisungsoperator =
verwechseln. Nachdem das Programm überprüft hat, ob die
Variablen gleich sind, prüft es in Zeile 21, ob x
größer ist als y
, und in Zeile 24, ob x
kleiner ist als y
. Wenn bei Ihnen der Eindruck entsteht, dass diese Verfahrensweise
etwas umständlich ist, haben Sie durchaus recht. Im nächsten Programm zeige ich
Ihnen, wie Sie diese Aufgabe etwas effizienter lösen können. Aber erst einmal sollten
Sie dieses Programm mit verschiedenen Werten für x
und y
ausführen und die
Ergebnisse begutachten.
Es wird Ihnen aufgefallen sein, dass die Anweisungen
in derif-
Bedingung eingerückt sind. Dies ist allgemein üblich,
um die Lesbarkeit zu erhöhen.
Eine if
-Anweisung kann optional eine else
-Bedingung umfassen. Die else
-
Bedingung wird folgendermaßen mit aufgenommen:
if (Ausdruck)
Anweisung1;
else
Anweisung2;
Wenn Ausdruck
zu wahr
ausgewertet wird, wird Anweisung1
ausgeführt. Wenn
Ausdruck
zu unwahr
ausgewertet wird, fährt das Programm mit der else
-Anweisung,
das heißt Anweisung2,
fort. Beide Anweisungen, Anweisung1
und Anweisung2
, können
Verbundanweisungen oder Blöcke sein.
Listing 3.4 ist eine Neufassung des Programms aus Listing 3.3 und enthält diesmal
eine if
-Anweisung mit einer else
-Bedingung.
Listing 3.4: Eine if-Anweisung mit einer else-Bedingung.
1: /* Beispiel für eine if-Anweisung mit einer else-Bedingung */
2:
3: #include <stdio.h>
4:
5: int x, y;
6:
7: int main(void)
8: {
9: /* Liest zwei Werte ein, die getestet werden */
10:
11: printf("\nGeben Sie einen Integer-Wert für x ein: ");
12: scanf("%d", &x);
13: printf("\nGeben Sie einen Integer-Wert für y ein: ");
14: scanf("%d", &y);
15:
16: /* Testet die Werte und gibt das Ergebnis aus. */
17:
18: if (x == y)
19: printf("x ist gleich y\n");
20: else
21: if (x > y)
22: printf("x ist größer als y\n");
23: else
24: printf("x ist kleiner als y\n");
25:
26: return 0;
27: }
Geben Sie einen Integer-Wert für x ein: 99
Geben Sie einen Integer-Wert für y ein: 8
x ist größer als y
Geben Sie einen Integer-Wert für x ein: 8
Geben Sie einen Integer-Wert für y ein: 99
x ist kleiner als y
Geben Sie einen Integer-Wert für x ein: 99
Geben Sie einen Integer-Wert für y ein: 99
x ist gleich y
Die Zeilen 18 bis 24 weichen etwas vom vorherigen Listing ab. Zeile 18 prüft immer
noch, ob x
gleich y
ist. Wenn diese Bedingung erfüllt ist, erscheint x ist gleich y
auf
dem Bildschirm, wie in Listing 3.3. Dann allerdings endet das Programm und die
Zeilen 20 bis 24 werden nicht ausgeführt. Zeile 21 wird nur ausgeführt, wenn x
nicht
gleich y
ist oder wenn, um genau zu sein, der Ausdruck »x ist gleich y« unwahr ist.
Wenn x
ungleich y
ist, prüft Zeile 21, ob x
größer als y
ist. Wenn ja, gibt Zeile 22 die
Nachricht x ist größer als y
aus. Andernfalls (engl. else
) wird Zeile 24 ausgeführt.
Listing 3.4 verwendet eine verschachtelte if
-Anweisung. Verschachteln bedeutet,
eine oder mehrere C-Anweisungen in einer anderen C-Anweisung unterzubringen. Im
Fall von Listing 3.4 ist eine if
-Anweisung Teil der else
-Bedingung der ersten if
-
Anweisung.
if( Ausdruck )
Anweisung1;
Naechste_Anweisung;
Dies ist die einfachste if
-Anweisung. Wenn Ausdruck
wahr ist, wird Anweisung1
ausgeführt. Ist Ausdruck
nicht wahr, wird Anweisung1
ignoriert.
if( Ausdruck )
Anweisung1;
else
Anweisung2;
Naechste_Anweisung;
Dies ist die am häufigsten verwendete if
-Anweisung. Wenn Ausdruck
wahr
ergibt, wird
Anweisung1
ausgeführt. Andernfalls wird Anweisung2
ausgeführt
if( Ausdruck1 )
Anweisung1;
else if( Ausdruck2 )
Anweisung2;
else
Anweisung3;
Naechste_Anweisung;
Das obige Beispiel ist eine verschachtelte if
-Anweisung. Wenn der erste Ausdruck,
Ausdruck1
, wahr ist, wird Anweisung1
ausgeführt, bevor das Programm mit
Naechste_Anweisung
fortfährt. Ist der erste Ausdruck nicht wahr, wird der zweite
Ausdruck, Ausdruck2
, geprüft. Wenn der erste Ausdruck nicht wahr und der zweite
wahr ist, wird Anweisung2
ausgeführt. Wenn beide Ausdrücke falsch sind, wird
Anweisung3
ausgeführt. Nur eine der drei Anweisungen wird ausgeführt.
if( gehalt > 450000 )
steuer = .30;
else
steuer = .25;
if( alter < 18 )
printf("Minderjaehriger");
else if( alter < 65 )
printf("Erwachsener");
else
printf( "Senior");
Denken Sie daran, dass Ausdrücke mit Vergleichsoperatoren C-Ausdrücke sind, die
per definitionem einen Integer-Wert als Ergebnis haben. Sie sind als Ergebnis
entweder wahr (1
) oder unwahr (0
). Meistens werden solche relationalen Ausdrücke in
if
-Anweisungen oder anderen Bedingungskonstruktionen verwendet, aber man kann
sie auch als rein numerische Werte verwenden. Sehen Sie dazu ein Beispiel.
Listing 3.5: Relationale Ausdrücke auswerten.
1: /* Beispiel für die Auswertung relationaler Ausdrücke */
2:
3: #include <stdio.h>
4:
5: int a;
6:
7: int main(void)
8: {
9: a = (5 == 5); /* hat als Ergebnis 1 */
10: printf("\na = (5 == 5)\na = %d", a);
11:
12: a = (5 != 5); /* hat als Ergebnis 0 */
13: printf("\na = (5 != 5)\na = %d", a);
14:
15: a = (12 == 12) + (5 != 1); /* hat als Ergebnis 1 + 1 */
16: printf("\na = (12 == 12) + (5 != 1)\na = %d\n", a);
17: return 0;
18: }
a = (5 == 5)
a = 1
a = (5 != 5)
a = 0
a = (12 == 12) + (5 != 1)
a = 2
Die Ausgabe dieses Listings mag auf den ersten Blick etwas verwirrend erscheinen.
Denken Sie daran, dass der häufigste Fehler bei der Verwendung der
Vergleichsoperatoren darin besteht, das einfache Gleichheitszeichen (den
Zuweisungsoperator) mit dem doppelten Gleichheitszeichens zu verwechseln. Der
folgende Ausdruck ergibt 5 (und weist den Wert 5
der Variablen x
zu):
x = 5
Dagegen ist das Ergebnis des folgenden Ausdrucks entweder 0
oder 1
(je nachdem, ob
x
gleich 5
ist oder nicht); der Wert von x
wird nicht geändert.
x == 5
if (x = 5)
printf("x ist gleich 5");
schreiben, wird die Nachricht immer ausgegeben, da der mit der if
-Anweisung
geprüfte Ausdruck immer wahr ist, unabhängig davon, was der ursprüngliche Wert
von x
war. Zum Glück können Sie angeben, dass beim Kompilieren alle Warnungen
angezeigt werden sollen (mit gcc -Wall
wie am Tag 1 beschrieben). Dann gibt gcc die
folgende Warnung aus: »suggest parentheses around assignment used as truth
value«
.
Wenn Sie mit diesem Wissen Listing 3.5 erneut betrachten, werden Sie verstehen,
warum a
die jeweiligen Werte annimmt. In Zeile 9 ist der Wert 5
gleich 5
, so dass a
der Wahrheitswert 1
zugewiesen wird. In Zeile 12 ist die Anweisung »5
ist ungleich 5
«
falsch, so dass a
der Wert 0
zugewiesen wird.
Fassen wir noch einmal zusammen: Vergleichsoperatoren werden benutzt, um
relationale Ausdrücke zu erzeugen, die Fragen zu den Beziehungen zwischen den
Ausdrücken stellen. Der von einem relationalen Ausdruck zurückgegebene Wert ist
numerischer Art und lautet entweder 1
(für wahr) oder 0
(für unwahr).
Wie die bereits besprochenen mathematischen Operatoren werden auch bei den Vergleichsoperatoren Prioritäten vergeben, die festlegen, in welcher Reihenfolge die Operatoren in einem Ausdruck mit mehreren Operatoren ausgeführt werden. Und auch hier können Sie mit Klammern darauf Einfluss nehmen, in welcher Reihenfolge die Operatoren des relationalen Ausdrucks ausgeführt werden sollen. Der Abschnitt »Übersicht der Operator-Rangfolge« gegen Ende der heutigen Lektion gibt Ihnen einen Gesamtüberblick über die Prioritäten aller C-Operatoren.
Zuerst sei gesagt, dass Vergleichsoperatoren in der Rangfolge unter den
mathematischen Operatoren stehen. Wenn Sie beispielsweise nachfolgenden Code
aufsetzen, wird zuerst 2
zu x
addiert und anschließend das Ergebnis mit y
verglichen:
if (x + 2 > y)
Dies entspricht der folgenden Zeile, die ein gutes Beispiel dafür ist, wie man mit Klammern mehr Klarheit schaffen kann:
if ((x + 2) > y)
Die Klammern um (x+2)
sind zwar aus der Sicht des C-Compilers nicht erforderlich,
machen aber besonders deutlich, dass die Summe von x
und 2
mit y
verglichen
werden soll.
Auch unter den Vergleichsoperatoren gibt es eine Rangfolge, wie Tabelle 3.6 zeigt.
x == y > z
x == (y > z)
da C zuerst den Ausdruck y > z
auswertet und dann feststellt, ob dieser Wert
(entweder 0
oder 1
) gleich x
ist. Sie werden Konstrukte dieser Art sicher selten, wenn
überhaupt anwenden, aber Sie sollten sie kennen.
Manchmal werden Sie sich gezwungen sehen, mehr als eine vergleichende Frage gleichzeitig zu stellen. Zum Beispiel: »Wenn es 7:00 Uhr ist, ein Wochentag und ich keinen Urlaub habe, dann soll der Wecker läuten.« Mit den logischen Operatoren in C können Sie zwei oder mehr relationale Ausdrücke in einem einzigen Ausdruck zusammenfassen, der dann entweder wahr oder unwahr ist. Tabelle 3.7 stellt Ihnen die drei logischen Operatoren von C vor.
Die Funktionsweise dieser logischen Operatoren ist in Tabelle 3.8 erläutert.
Tabelle 3.8: Anwendungsbeispiele für die logischen Operatoren von C.
Dieser Tabelle können Sie entnehmen, dass Ausdrücke, die logische Operatoren enthalten, entweder wahr oder unwahr sind, je nachdem ob ihr(e) Operand(en) vom Wert her wahr/falsch ist (sind). Tabelle 3.9 zeigt einige konkrete Code-Beispiele.
Sie können auch Ausdrücke erzeugen, die mehrere logische Operatoren enthalten.
Um zum Beispiel zu fragen, ob x
gleich 2, 3 oder 4 ist, könnten Sie schreiben:
(x == 2) || (x == 3) || (x == 4)
Die logischen Operatoren erlauben häufig, eine Frage auf mehr als eine Art zu stellen.
Angenommen x
ist eine Integer-Variable, dann gibt es für die obige Frage zwei weitere
Schreibweisen:
(x > 1) && (x < 5)
(x >= 2) && (x <= 4)
Sie haben bereits gelernt, dass relationale Ausdrücke in C 0
zurückgeben, wenn sie
unwahr sind, und 1
, wenn sie wahr sind. In diesem Zusammenhang sollte man sich
darüber im Klaren sein, dass jeder numerische Wert als entweder wahr oder unwahr
interpretiert wird, wenn er in C-Ausdrücken oder -Anweisungen verwendet wird, die
einen logischen Wert (das heißt, wahr oder unwahr) erwarten. Die Regeln dafür lauten:
Sehen Sie dazu das folgende Beispiel, in dem der Wert von x
ausgegeben wird:
x = 125;
if (x)
printf("%d", x);
Da x
ein Wert ungleich Null ist, interpretiert die if
-Anweisung den Ausdruck (x)
als
wahr. Dies lässt sich mit folgender Schreibweise für alle C-Ausdrücke noch weiter
verallgemeinern:
(Ausdruck)
entspricht der folgenden Schreibweise
(Ausdruck != 0)
Beide werden als wahr
ausgewertet, wenn Ausdruck
ungleich Null ist, und als falsch
,
wenn Ausdruck
0
ist. Unter Zuhilfenahme des NOT-Operators (!
) können Sie auch
Folgendes schreiben:
(!Ausdruck)
(Ausdruck == 0)
Wie Sie vielleicht schon geraten haben, gibt es auch unter den logischen Operatoren
in C eine Rangfolge, sowohl untereinander als auch zu den anderen Operatoren. Die
Priorität des !
-Operators entspricht der der unären mathematischen Operatoren ++
und --
. Deshalb steht !
in der Rangfolge höher als alle Vergleichsoperatoren und alle
binären mathematischen Operatoren.
Im Gegensatz dazu haben die Operatoren &&
und ||
eine viel niedrigere Priorität,
niedriger als alle mathematischen und relationalen Operatoren, wenn auch &&
eine
höhere Priorität hat als ||
. Wie bei allen anderen C-Operatoren können Klammern
auch bei den logischen Operatoren die Reihenfolge der Auswertung ändern.
Betrachten Sie dazu folgendes Beispiel:
Sie wollen einen logischen Ausdruck schreiben, der drei einzelne Vergleiche vornimmt:
Der ganze logische Ausdruck soll wahr
ergeben, wenn Bedingung 3 und entweder
Bedingung 1 oder 2 wahr ist. In diesem Fall könnten Sie schreiben:
a < b || a < c && c < d
Dieser Ausdruck entspricht vom Ergebnis her jedoch nicht Ihren Erwartungen. Da der
&&
-Operator eine höhere Priorität hat als ||
, ist der Ausdruck äquivalent zu
a < b || (a < c && c < d)
und wird wahr, wenn (a < b)
wahr ist, unabhängig davon, ob die Beziehungen (a < c)
und (c < d)
wahr sind. Deshalb müssen Sie
(a < b || a < c) && c < d
schreiben, um zu erzwingen, dass ||
vor dem &&
ausgewertet wird. Sehen Sie dazu ein
Beispiel (Listing 3.6), in dem beide Schreibweisen des Ausdrucks ausgewertet werden.
Die Variablen sind so gesetzt, dass bei korrekter Schreibweise der Ausdruck falsch
(0
)
ergeben sollte.
Listing 3.6: Rangfolge der logischen Operatoren.
1: #include <stdio.h>
2:
3: /* Initialisierung der Variablen. Beachten Sie, dass c nicht */
4: /* kleiner ist als d, eine der Bedingungen, auf die getestet wird. */
5: /* Deshalb sollte der gesamte Ausdruck falsch ergeben.*/
6:
7: int a = 5, b = 6, c = 5, d = 1;
8: int x;
9:
10: int main(void)
11: {
12: /* Auswertung des Ausdrucks ohne Klammern */
13:
14: x = a < b || a < c && c < d;
15: printf("\nOhne Klammern lautet das Ergebnis des Ausdrucks %d", x);
16:
17: /* Auswertung des Ausdrucks mit Klammern */
18:
19: x = (a < b || a < c) && c < d;
20: printf("\nMit Klammern lautet das Ergebnis des Ausdrucks %d\n", x);
21: return 0;
22: }
Ohne Klammern lautet das Ergebnis des Ausdrucks 1
Mit Klammern lautet das Ergebnis des Ausdrucks 0
Geben Sie dieses Listing ein und führen Sie es aus. Achten Sie auf die Warnung vom gcc:
list0306.c:14: warning: suggest parentheses around && within ||
In diesem Fall können Sie die Warnung ignorieren, da wir hier das Problem veranschaulichen wollen, über das sich der Compiler beschwert. Wichtiger ist jedoch, dass die beiden Werte, die für den Ausdruck ausgegeben werden, unterschiedlich sind, obwohl der einzige Unterschied zwischen ihnen darin besteht, dass die Anweisung in Zeile 19 Klammern aufweist.
Dieses Programm initialisiert in Zeile 7 vier Variablen mit Werten, die in den
Vergleichen herangezogen werden. Zeile 8 deklariert x
für die Speicherung und die
Ausgabe der Ergebnisse. Zeile 14 und 19 verwenden die logischen Operatoren. Zeile
14 verwendet keine Klammern, so dass das Ergebnis von der Rangfolge der
Operatoren abhängt. In diesem Fall entsprechen die Ergebnisse nicht Ihren
Erwartungen. Zeile 19 hat diese Klammern gesetzt, um die Reihenfolge, in der die
Ausdrücke ausgewertet werden, zu ändern.
Die zusammengesetzten Zuweisungsoperatoren in C bieten Ihnen die Möglichkeit,
eine binäre mathematische Operation mit einer Zuweisung zu kombinieren.
Angenommen Sie wollten zum Beispiel den Wert x
um 5
erhöhen oder, anders
ausgedrückt, 5
mit x
addieren und das Ergebnis dann x zuweisen. Dann könnten Sie
schreiben:
x = x + 5;
Unter Verwendung eines zusammengesetzten Zuweisungsoperators, den Sie sich am besten als eine verkürzte Form der Zuweisung vorstellen können, würden Sie schreiben:
x += 5;
In allgemeinerer Form lautet die Syntax für zusammengesetzte Zuweisungsoperatoren
wie folgt (wobei op
für einen binären Operator steht):
ausdr1 op= ausdr2
Dies entspricht der folgenden Schreibweise:
ausdr1 = ausdr1 op ausdr2;
Sie können den Zuweisungsoperator mit allen fünf mathematischen Operatoren, die wir oben besprochen haben, kombinieren. In Tabelle 3.10 finden Sie einige Beispiele.
Zusammengesetzte Operatoren reduzieren den Schreibaufwand. Die Vorteile zeigen
sich vor allem, wenn die Variable links des Zuweisungsoperators einen langen Namen
hat. Wie alle anderen Zuweisungen ist auch eine zusammengesetzte Zuweisung ein
Ausdruck und hat den Wert, der der linken Seite zugewiesen wurde, als Ergebnis. Die
Ausführung der folgenden Anweisungen ergibt für beide, x
und z
, den Wert 14:
x = 12;
z = x += 2;
Der Bedingungsoperator ist der einzige ternäre Operator in C, das heißt der einzige Operator, der drei Operanden benötigt. Seine Syntax lautet:
ausdr1 ? ausdr2 : ausdr3;
Wenn ausdr1
wahr ist (das heißt einen Wert ungleich Null hat), erhält der gesamte
Ausdruck den Wert von ausdr2
. Wenn ausdr1
falsch (das heißt, Null) ist, erhält der
gesamte Ausdruck den Wert von ausdr3
. So weist zum Beispiel die folgende
Anweisung x
den Wert 1
zu, wenn y
wahr ist, oder den Wert 100
, wenn y
falsch ist:
x = y ? 1 : 100;
Dementsprechend können Sie wie folgt z mit der größeren der beiden Variablen x oder y gleichsetzen:
z = (x > y) ? x : y;
Vielleicht ist Ihnen aufgefallen, dass der Bedingungsoperator sehr stark an die if
-
Anweisung erinnert. Die obige Anweisung ließe sich auch wie folgt schreiben:
if (x > y)
z = x;
else
z = y;
Der Bedingungsoperator kann eine if...else
-Konstruktion nicht in allen Fällen
ersetzen, er ist aber wesentlich kürzer. Außerdem kann der Bedingungsoperator auch
dort verwendet werden, wo eine if
-Anweisung nicht möglich ist, zum Beispiel
innerhalb eines Aufrufs einer anderen Funktion, etwa einer printf()
-Anweisung.
printf( "Der größere Wert lautet %d", ((x > y) ? x : y) );
Das Komma wird in C häufig als ein einfaches Satzzeichen verwendet, das dazu dient, Variablendeklarationen, Funktionsargumente etc. voneinander zu trennen. In bestimmten Situationen jedoch fungiert das Komma als Operator und nicht nur als einfaches Trennzeichen. Sie können einen Ausdruck bilden, indem Sie zwei Unterausdrücke durch ein Komma trennen. Das Ergebnis sieht folgendermaßen aus:
Die folgende Anweisung weist x
den Wert b
zu, inkrementiert a
und inkrementiert
dann b
:
x = (a++ , b++);
Da der ++
-Operator im Postfix-Modus verwendet wird, wird der Wert von b
der
Variablen x
vor seiner Inkrementierung zugewiesen. Hier sind Klammern nötig, da
der Komma-Operator eine niedrige Priorität hat, sogar noch niedriger als der
Zuweisungsoperator.
Wie Sie morgen sehen werden, wird der Komma-Operator am häufigsten in for
-
Anweisungen verwendet.
Tabelle 3.11 gibt eine Übersicht über alle C-Operatoren in der Reihenfolge ihrer absteigenden Priorität. Operatoren der gleichen Priorität stehen in einer Zeile.
Diese Tabelle eignet sich gut als Referenz, bis Sie mit der Rangfolge der Operatoren besser vertraut sind. Sie werden Sie wahrscheinlich später benötigen.
Die heutige Lektion war sehr umfangreich. Sie haben gelernt, was eine C-Anweisung ist, dass Whitespace-Zeichen vom Compiler nicht berücksichtigt werden und dass Anweisungen immer mit einem Semikolon abschließen. Außerdem wissen Sie jetzt, dass eine Verbundanweisung (oder Block), die aus zwei oder mehr Anweisungen in geschweiften Klammern besteht, überall dort eingesetzt werden kann, wo auch eine einfache Anweisung möglich ist.
Viele Anweisungen bestehen aus einer Kombination von Ausdrücken und Operatoren. Denken Sie daran, dass man unter dem Begriff »Ausdruck« alles zusammenfasst, was einen numerischen Wert zurückliefert. Komplexe Ausdrücke können aus vielen einfacheren Ausdrücken zusammengesetzt sein, die dann Unterausdrücke genannt werden.
Operatoren sind C-Symbole, die dem Computer mitteilen, eine Operation auf einem oder mehreren Ausdrücken auszuführen. Einige Operatoren sind unär, das heißt, sie benötigen nur einen Operanden. Die meisten C-Operatoren sind jedoch binär und erfordern zwei Operanden. Ein Operator, der Bedingungsoperator, ist sogar ternär. Innerhalb der Operatoren in C gibt es eine feste Hierarchie der Prioritäten, die festlegt, in welcher Reihenfolge die Operationen in einem Ausdruck auszuführen sind, der mehrere Operatoren enthält.
Die heute besprochenen C-Operatoren lassen sich in drei Kategorien unterteilen:
wahr/unwahr
-Ausdrücke anwenden. Denken
Sie daran, dass C 0
und 1
verwendet, um unwahr
und wahr
darzustellen, und dass
jeder Wert ungleich Null als wahr interpretiert wird.
Sie wurden mit den Grundlagen der if
-Anweisung bekannt gemacht, die es Ihnen
ermöglicht, auf Basis der Auswertung von relationalen Ausdrücken den
Programmfluss zu steuern.
Frage:
Welche Auswirkung haben Leerzeichen und leere Zeilen auf die Ausführung Ihres
Programms?
Antwort:
Whitespace-Zeichen (leere Zeilen, Leerzeichen, Tabulatoren) machen Ihren
Quellcode lesbarer. Wenn das Programm kompiliert wird, werden die
Whitespace-Zeichen entfernt, haben also keinen Einfluss auf das ausführbare
Programm. Deshalb sollten Sie möglichst verschwenderisch mit Whitespace-
Zeichen umgehen, um Ihre Programme so lesbar wie möglich zu machen.
Frage:
Ist es ratsamer, eine komplexe if
-Anweisung zu formulieren oder mehrere if
-
Anweisungen zu verschachteln?
Antwort:
Ihr Code sollte leicht verständlich sein. Wenn Sie if
-Anweisungen
verschachteln, werden diese nach den oben ausgeführten Regeln ausgewertet.
Wenn Sie eine einzige komplexe if
-Anweisung verwenden, werden die
Ausdrücke nur soweit ausgewertet, bis der gesamte Ausdruck falsch
ergibt.
Frage:
Was ist der Unterschied zwischen unären und binären Operatoren?
Antwort:
Wie die Namen schon verraten, benötigen unäre Operatoren nur eine
Variable, binäre Operatoren hingegen zwei.
Frage:
Ist der Subtraktionsoperator (-
) binär oder unär?
Antwort:
Er ist beides! Der Compiler ist intelligent genug, um an der Anzahl der
Variablen zu erkennen, welchen Operator Sie gerade meinen. In der
folgenden Anweisung ist er unär:
x = -y;
wohingegen er hier binär verwendet wird:
x = a - b;
Frage:
Werden negative Zahlen als wahr oder als unwahr betrachtet?
Antwort:
Zur Erinnerung: 0
steht für unwahr
und jeder andere Wert steht für wahr
. Dazu
gehören dann auch die negativen Zahlen.
Der Workshop enthält Quizfragen, die Ihnen helfen sollen, Ihr Wissen zu festigen, sowie Übungen, die Sie anregen sollen, das Gelernte umzusetzen und eigene Erfahrungen zu sammeln. Die Lösungen zu den Fragen und den Übungen finden Sie in Anhang C.
x = 5 + 8;
x
hat den Wert 10
. Wie lauten die Werte für x
und a
,
nachdem jede der beiden folgenden Anweisungen getrennt ausgeführt wurde?
a = x++;
a = ++x;
10 % 3
?
5 + 3 * 8 / 2 + 2
?
16
lautet.
unwahr
ausgewertet wird?
#include <stdio.h>
int x,y;int main(void){ printf(
"\nGeben Sie zwei Zahlen ein");scanf(
"%d %d",&x,&y);printf(
"\n\n%d ist größer",(x>y)?x:y);return 0;}
if
-Anweisung, die der Variablen y
den Wert von x
nur dann
zuweist, wenn x
zwischen 1
und 20
ist. Lassen Sie y
unverändert, wenn x nicht in
diesem Wertebereich liegt.
if
-Anweisungen um und
verwenden Sie dazu eine einfache if
-Anweisung und logische Operatoren.
if (x < 1)
if ( x > 10 )
anweisung;
(1 + 2 * 3)
10 % 3 * 3 - (1 + 2)
((1 + 2) * 3)
(5 == 5)
(x = 5)
x = 4
, y = 6
und z = 2
. Stellen Sie fest, ob die folgenden
Ausdrücke wahr oder falsch sind.
if( x == 4)
if(x != y - z)
if(z = 1)
if(y)
if
-Anweisung, die feststellt, ob jemand juristisch gesehen ein
Erwachsener (Alter 18) ist, aber noch nicht das Rentenalter erreicht hat (Alter 65).
/* ein Programm mit Problemen... */
#include <stdio.h>
int x= 1:
int main(void)
{
if( x = 1);
printf(" x ist gleich 1" );
andernfalls
printf(" x ist ungleich 1");
return 0;
}