How to Work with Variables, Data Types, and Arithmetic Expressions in the C Programming Language

C verfügt über eine Vielzahl von mathematischen Operatoren, die Sie verwenden können, um Ihre Daten zu manipulieren. In diesem Kapitel aus Programming in C, 4th Edition, behandelt Stephen G. Kochan die Datentypen int, float, double, char und _Bool, die Modifizierung von Datentypen mit short, long und long long, die Regeln für die Benennung von Variablen, grundlegende mathematische Operatoren und arithmetische Ausdrücke sowie das Typ-Casting.

Die wahre Stärke der von Ihnen erstellten Programme liegt in der Manipulation von Daten. Um diese Leistung wirklich nutzen zu können, müssen Sie die verschiedenen Datentypen, die Sie verwenden können, sowie die Erstellung und Benennung von Variablen besser verstehen. C verfügt über eine Vielzahl von mathematischen Operatoren, mit denen Sie Ihre Daten manipulieren können. In diesem Kapitel werden Sie die folgenden Themen behandeln:

  • Die Datentypen int, float, double, char und _Bool
  • Modifizieren von Datentypen mit short, long, und long long
  • Die Regeln für die Benennung von Variablen
  • Grundlegende mathematische Operatoren und arithmetische Ausdrücke
  • Typenzuordnung

Verstehen von Datentypen und Konstanten

Sie haben bereits den C-Grunddatentyp int kennengelernt. Wie Sie sich erinnern werden, kann eine Variable vom Typ int nur für ganzzahlige Werte verwendet werden, d.h. für Werte, die keine Dezimalstellen enthalten.

Die Programmiersprache C bietet vier weitere grundlegende Datentypen: float, double, char und _Bool. Eine Variable, die mit dem Typ float deklariert ist, kann zur Speicherung von Fließkommazahlen (Werte mit Nachkommastellen) verwendet werden. Der Typ double entspricht dem Typ float, nur mit etwa doppelt so hoher Genauigkeit. Der Datentyp char kann zum Speichern eines einzelnen Zeichens verwendet werden, z. B. des Buchstabens ‚a‘, der Ziffer ‚6‘ oder eines Semikolons (‚;‘) (mehr dazu später). Schließlich kann der Datentyp _Bool verwendet werden, um nur die Werte 0 oder 1 zu speichern. Variablen dieses Typs werden verwendet, um eine Ein/Aus-, Ja/Nein- oder Wahr/Falsch-Situation zu kennzeichnen. Diese entweder-oder-Entscheidungen sind auch als binäre Entscheidungen bekannt.

In C wird jede Zahl, jedes einzelne Zeichen oder jede Zeichenkette als Konstante bezeichnet. Zum Beispiel stellt die Zahl 58 einen konstanten ganzzahligen Wert dar. Die Zeichenkette „Programming in C is fun.\n“ ist ein Beispiel für eine konstante Zeichenkette. Ausdrücke, die ausschließlich aus konstanten Werten bestehen, werden als konstante Ausdrücke bezeichnet. So ist der Ausdruck

128 + 7 - 17

ein konstanter Ausdruck, weil jeder der Ausdrücke des Ausdrucks ein konstanter Wert ist. Wäre i jedoch als Integer-Variable deklariert, würde der Ausdruck

128 + 7 – i

keinen konstanten Ausdruck darstellen, da sich sein Wert je nach dem Wert von i ändern würde. Wenn i gleich 10 ist, ist der Ausdruck gleich 125, aber wenn i gleich 200 ist, ist der Ausdruck gleich -65.

Der Integer-Typ int

In C besteht eine Integer-Konstante aus einer Folge von einer oder mehreren Ziffern. Ein Minuszeichen vor der Folge zeigt an, dass der Wert negativ ist. Die Werte 158, -10 und 0 sind allesamt gültige Beispiele für Integer-Konstanten. Zwischen den Ziffern dürfen keine Leerzeichen eingefügt werden, und Werte über 999 können nicht durch Kommas ausgedrückt werden. (Der Wert 12.000 ist also keine gültige Integer-Konstante und muss als 12000 geschrieben werden.)

Zwei spezielle Formate in C ermöglichen es, Integer-Konstanten in einer anderen Basis als der Dezimalbasis (Basis 10) auszudrücken. Wenn die erste Ziffer des Integer-Wertes eine 0 ist, wird der Integer-Wert in Oktalschreibweise, d.h. zur Basis 8, angegeben. In diesem Fall müssen die verbleibenden Ziffern des Wertes gültige Basis-8-Ziffern sein, d. h. sie müssen 0-7 sein. Um also den Wert 50 zur Basis 8 in C auszudrücken, der dem Wert 40 in Dezimalzahlen entspricht, wird die Notation 050 verwendet. In ähnlicher Weise steht die Oktalkonstante 0177 für den Dezimalwert 127 (1 × 64 + 7 × 8 + 7). Ein ganzzahliger Wert kann auf dem Terminal in oktaler Notation angezeigt werden, indem die Formatzeichen %o in der Formatzeichenfolge einer printf()-Anweisung verwendet werden. In einem solchen Fall wird der Wert in oktaler Schreibweise ohne führende Null angezeigt. Das Formatzeichen %#o bewirkt, dass vor einem oktalen Wert eine führende Null angezeigt wird.

Wenn einer Integer-Konstante eine Null und der Buchstabe x (entweder in Klein- oder Großbuchstaben) vorangestellt wird, wird der Wert in hexadezimaler Notation (Basis 16) angegeben. Unmittelbar nach dem Buchstaben x folgen die Ziffern des hexadezimalen Wertes, der sich aus den Ziffern 0-9 und den Buchstaben a-f (oder A-F) zusammensetzen kann. Die Buchstaben stehen jeweils für die Werte 10-15. Um also einer Integer-Variablen namens rgbColor den Hexadezimalwert FFEF0D zuzuweisen, kann die Anweisung

rgbColor = 0xFFEF0D;

verwendet werden. Die Formatzeichen %x zeigen einen Wert im Hexadezimalformat ohne das führende 0x an, wobei die Kleinbuchstaben a-f für die Hexadezimalziffern verwendet werden. Um den Wert mit dem führenden 0x anzuzeigen, verwenden Sie die Formatzeichen %#x, wie im Folgenden:

printf ("Color is %#x\n", rgbColor);

Ein großes x, wie in %X oder %#X, kann verwendet werden, um das führende x und die darauf folgenden hexadezimalen Ziffern mit Großbuchstaben anzuzeigen.

Speichergrößen und -bereiche

Jeder Wert, egal ob es sich um ein Zeichen, eine Ganzzahl oder eine Fließkommazahl handelt, hat einen damit verbundenen Wertebereich. Dieser Bereich hat mit der Menge an Speicherplatz zu tun, die für die Speicherung eines bestimmten Datentyps vorgesehen ist. Im Allgemeinen ist diese Menge nicht in der Sprache definiert. Er hängt in der Regel von dem Computer ab, mit dem Sie arbeiten, und wird daher als implementierungs- oder maschinenabhängig bezeichnet. Eine ganze Zahl kann beispielsweise 32 Bits auf Ihrem Computer belegen, oder sie kann in 64 Bits gespeichert werden. Sie sollten niemals Programme schreiben, die Annahmen über die Größe Ihrer Datentypen machen. Es ist jedoch garantiert, dass für jeden Grunddatentyp ein Mindestmaß an Speicherplatz zur Verfügung steht. So wird beispielsweise garantiert, dass ein Integer-Wert in mindestens 32 Bit Speicherplatz gespeichert wird, was auf vielen Computern der Größe eines „Wortes“ entspricht.

Der Gleitkomma-Typ float

Eine Variable, die als Typ float deklariert ist, kann zum Speichern von Werten mit Dezimalstellen verwendet werden. Eine Fließkomma-Konstante zeichnet sich durch das Vorhandensein eines Dezimalpunktes aus. Sie können die Ziffern vor dem Dezimalpunkt oder die Ziffern nach dem Dezimalpunkt weglassen, aber natürlich können Sie nicht beide weglassen. Die Werte 3., 125.8 und -.0001 sind allesamt gültige Beispiele für Fließkommakonstanten. Um einen Fließkommawert auf dem Terminal anzuzeigen, werden die printf-Konvertierungszeichen %f verwendet.

Fließkommakonstanten können auch in wissenschaftlicher Notation ausgedrückt werden. Der Wert 1.7e4 ist ein Fließkommawert, der in dieser Notation ausgedrückt wird und den Wert 1.7 × 104 darstellt. Der Wert vor dem Buchstaben e wird als Mantisse bezeichnet, während der nachfolgende Wert als Exponent bezeichnet wird. Dieser Exponent, dem ein fakultatives Plus- oder Minuszeichen vorangestellt werden kann, steht für die 10er-Potenz, mit der die Mantisse zu multiplizieren ist. Bei der Konstante 2,25e-3 ist also 2,25 der Wert der Mantisse und -3 der Wert des Exponenten. Diese Konstante entspricht dem Wert 2,25 × 10-3, also 0,00225. Der Buchstabe e, der die Mantisse vom Exponenten trennt, kann übrigens sowohl klein als auch groß geschrieben werden.

Um einen Wert in wissenschaftlicher Notation darzustellen, sollten die Formatzeichen %e in der printf()-Formatzeichenfolge angegeben werden. Die printf()-Formatzeichen %g können verwendet werden, um printf() entscheiden zu lassen, ob der Fließkommawert in normaler Fließkomma-Notation oder in wissenschaftlicher Notation angezeigt werden soll. Diese Entscheidung basiert auf dem Wert des Exponenten: Wenn er kleiner als -4 oder größer als 5 ist, wird das Format %e (wissenschaftliche Notation) verwendet; andernfalls wird das Format %f verwendet.

Verwenden Sie die Zeichen des Formats %g für die Anzeige von Fließkommazahlen – es erzeugt die ästhetisch ansprechendste Ausgabe.

Eine hexadezimale Fließkommakonstante besteht aus einem führenden 0x oder 0X, gefolgt von einer oder mehreren dezimalen oder hexadezimalen Ziffern, gefolgt von einem p oder P, gefolgt von einem optional vorzeichenbehafteten binären Exponenten. Zum Beispiel steht 0x0.3p10 für den Wert 3/16 × 210 = 0.5.

Der erweiterte Präzisionstyp double

Der Typ double ist dem Typ float sehr ähnlich, wird aber immer dann verwendet, wenn der von einer float-Variablen bereitgestellte Bereich nicht ausreichend ist. Variablen, die zum Typ double deklariert sind, können etwa doppelt so viele signifikante Stellen speichern wie eine Variable vom Typ float. Die meisten Computer stellen double-Werte mit 64 Bit dar.

Sofern nicht anders angegeben, werden alle Fließkomma-Konstanten vom C-Compiler als double-Werte angenommen. Um eine Fließkommakonstante explizit auszudrücken, hängen Sie entweder ein f oder ein F an das Ende der Zahl an, wie folgt:

12.5f

Um einen Doppelwert anzuzeigen, können die Formatzeichen %f, %e oder %g verwendet werden, die die gleichen Formatzeichen sind, die auch für die Anzeige eines Fließkommawertes verwendet werden.

Der Einzelzeichentyp char

Eine char-Variable kann verwendet werden, um ein einzelnes Zeichen zu speichern.1 Eine Zeichenkonstante wird gebildet, indem das Zeichen in ein Paar einfacher Anführungszeichen eingeschlossen wird. So sind ‚a‘, ‚;‘ und ‚0‘ alles gültige Beispiele für Zeichenkonstanten. Die erste Konstante steht für den Buchstaben a, die zweite für ein Semikolon und die dritte für das Zeichen Null, das nicht mit der Zahl Null identisch ist. Verwechseln Sie eine Zeichenkonstante, bei der es sich um ein einzelnes Zeichen in einfachen Anführungszeichen handelt, nicht mit einer Zeichenkette, bei der es sich um eine beliebige Anzahl von Zeichen in doppelten Anführungszeichen handelt.

Die Zeichenkonstante ‚\n‘-das Newline-Zeichen- ist eine gültige Zeichenkonstante, auch wenn sie der zuvor zitierten Regel zu widersprechen scheint. Das liegt daran, dass das Backslash-Zeichen im C-System ein Sonderzeichen ist und eigentlich nicht als Zeichen zählt. Mit anderen Worten: Der C-Compiler behandelt das Zeichen „\n“ als ein einziges Zeichen, obwohl es eigentlich aus zwei Zeichen besteht. Es gibt noch weitere Sonderzeichen, die mit dem Backslash-Zeichen eingeleitet werden. Eine vollständige Liste finden Sie in Anhang A, „Zusammenfassung der Sprache C“.

Die Formatzeichen %c können in einem printf()-Aufruf verwendet werden, um den Wert einer char-Variablen auf dem Terminal anzuzeigen.

Der boolesche Datentyp _Bool

Eine _Bool-Variable ist in der Sprache so definiert, dass sie groß genug ist, um nur die Werte 0 und 1 zu speichern. Der genaue Speicherplatz, der verwendet wird, ist nicht spezifiziert. _Bool-Variablen werden in Programmen verwendet, die eine boolesche Bedingung angeben müssen. Eine Variable dieses Typs kann z.B. anzeigen, ob alle Daten aus einer Datei gelesen wurden.

Nach Konvention wird 0 verwendet, um einen falschen Wert anzuzeigen, und 1 zeigt einen wahren Wert an. Wenn Sie einer _Bool-Variablen einen Wert zuweisen, wird der Wert 0 in der Variablen als 0 gespeichert, während jeder Wert ungleich Null als 1 gespeichert wird.

Um die Arbeit mit _Bool-Variablen in Ihrem Programm zu erleichtern, definiert die Standard-Header-Datei <stdbool.h> die Werte bool, true und false. Ein Beispiel dafür finden Sie im Programm 5.10A in Kapitel 5, „Entscheidungen treffen“.

In Programm 3.1 werden die grundlegenden C-Datentypen verwendet.

Programm 3.1 Verwendung der grundlegenden Datentypen

Programm 3.1 Ausgabe

integerVar = 100floatingVar = 331.790009doubleVar = 8.440000e+11doubleVar = 8.44e+11charVar = WboolVar = 0;

Die erste Anweisung von Programm 3.1 deklariert die Variable integerVar als Ganzzahlvariable und weist ihr einen Anfangswert von 100 zu, als ob stattdessen die folgenden beiden Anweisungen verwendet worden wären:

int integerVar;integerVar = 100;

In der zweiten Zeile der Programmausgabe ist zu erkennen, dass der Wert 331,79, der floatingVar zugewiesen ist, tatsächlich als 331,790009 angezeigt wird. Der tatsächlich angezeigte Wert hängt von dem jeweiligen Computersystem ab, das Sie verwenden. Der Grund für diese Ungenauigkeit liegt in der besonderen Art und Weise, in der Zahlen intern im Computer dargestellt werden. Wahrscheinlich ist Ihnen die gleiche Art von Ungenauigkeit schon einmal beim Umgang mit Zahlen auf Ihrem Taschenrechner begegnet. Wenn Sie auf Ihrem Taschenrechner 1 durch 3 dividieren, erhalten Sie das Ergebnis .33333333, vielleicht mit ein paar zusätzlichen 3en am Ende. Die 3er-Kette ist die Annäherung des Taschenrechners an ein Drittel. Theoretisch müsste es eine unendliche Anzahl von 3en geben. Aber der Taschenrechner kann nur so viele Ziffern speichern, daher die inhärente Ungenauigkeit des Geräts. Die gleiche Art von Ungenauigkeit gilt auch hier: Bestimmte Fließkommawerte können im Speicher des Rechners nicht exakt dargestellt werden.

Bei der Anzeige der Werte von Float- oder Double-Variablen haben Sie die Wahl zwischen drei verschiedenen Formaten. Die %f-Zeichen werden verwendet, um Werte in einer Standardform darzustellen. Wenn nicht anders angegeben, zeigt printf() einen Float- oder Double-Wert immer auf sechs Dezimalstellen gerundet an. Wie Sie die Anzahl der angezeigten Dezimalstellen auswählen können, erfahren Sie später in diesem Kapitel.

Die %e-Zeichen werden verwendet, um den Wert einer Float- oder Double-Variablen in wissenschaftlicher Notation anzuzeigen. Auch hier werden sechs Nachkommastellen automatisch vom System angezeigt.

Mit den %g-Zeichen wählt printf() zwischen %f und %e und entfernt außerdem automatisch alle nachgestellten Nullen aus der Anzeige. Wenn dem Dezimalpunkt keine Ziffern folgen, wird er auch nicht angezeigt.

In der vorletzten printf()-Anweisung werden die %c-Zeichen verwendet, um das einzelne Zeichen ‚W‘ anzuzeigen, das Sie charVar bei der Deklaration der Variablen zugewiesen haben. Denken Sie daran, dass eine Zeichenkette (wie das erste Argument von printf()) von einem Paar doppelter Anführungszeichen eingeschlossen wird, während eine Zeichenkonstante immer von einem Paar einfacher Anführungszeichen eingeschlossen werden muss.

Die letzte printf()-Anweisung zeigt, dass der Wert einer _Bool-Variablen mit den Ganzzahlformatzeichen %i angezeigt werden kann.

Typangaben: long, long long, short, unsigned und signed

Wenn die Angabe long direkt vor der int-Deklaration steht, hat die deklarierte Integer-Variable auf einigen Computersystemen einen erweiterten Bereich. Ein Beispiel für eine long int-Deklaration könnte sein

long int factorial;

Damit wird die Variable factorial als Long-Integer-Variable deklariert. Wie bei Floats und Doubles hängt die besondere Genauigkeit einer Long-Variablen von Ihrem Computersystem ab. Auf vielen Systemen haben int und long int den gleichen Bereich und können beide zum Speichern von Integer-Werten mit einer Breite von bis zu 32 Bit (231 – 1 oder 2.147.483.647) verwendet werden.

Ein konstanter Wert vom Typ long int wird durch optionales Anhängen des Buchstabens L (Groß- oder Kleinbuchstabe) an das Ende einer Integer-Konstanten gebildet. Zwischen der Zahl und dem L sind keine Leerzeichen erlaubt. Die Deklaration

long int numberOfPoints = 131071100L;

deklariert also die Variable numberOfPoints zum Typ long int mit einem Anfangswert von 131.071.100.

Um den Wert eines long int mit printf() anzuzeigen, wird der Buchstabe l als Modifikator vor den Integer-Formatzeichen i, o und x verwendet. Das bedeutet, dass die Formatzeichen %li verwendet werden können, um den Wert eines long int im Dezimalformat anzuzeigen, die Zeichen %lo können den Wert im Oktalformat anzeigen, und die Zeichen %lx können den Wert im Hexadezimalformat anzeigen.

Es gibt auch einen Long-Long-Integer-Datentyp, so

long long int maxAllowedStorage;

deklariert die angegebene Variable als von der angegebenen erweiterten Genauigkeit, die garantiert mindestens 64 Bit breit ist. Anstelle eines einzelnen Buchstabens l werden zwei ls in der printf-Zeichenkette verwendet, um lange Ganzzahlen darzustellen, wie in „%lli“.

Der Long-Spezifizierer ist auch vor einer Double-Deklaration zulässig, wie folgt:

long double US_deficit_2004;

Eine lange Double-Konstante wird als Fließkomma-Konstante mit dem Buchstaben l oder L unmittelbar danach geschrieben, wie z.B.

1.234e+7L

Um ein langes Double darzustellen, wird der L-Modifizierer verwendet. So zeigt %Lf einen langen Double-Wert in Fließkomma-Notation an, %Le zeigt denselben Wert in wissenschaftlicher Notation an, und %Lg weist printf() an, zwischen %Lf und %Le zu wählen.

Der Spezifizierer short, wenn er vor die int-Deklaration gesetzt wird, teilt dem C-Compiler mit, dass die bestimmte Variable, die deklariert wird, verwendet wird, um ziemlich kleine Ganzzahlwerte zu speichern. Die Motivation für die Verwendung von short-Variablen ist in erster Linie die Einsparung von Speicherplatz, was in Situationen, in denen das Programm viel Speicher benötigt und der verfügbare Speicher begrenzt ist, ein Problem darstellen kann.

Auf einigen Rechnern benötigt eine short int-Variable nur halb so viel Speicherplatz wie eine normale int-Variable. In jedem Fall ist gewährleistet, dass der für einen short int zugewiesene Speicherplatz nicht weniger als 16 Bit beträgt.

Es gibt keine Möglichkeit, in C explizit eine Konstante vom Typ short int zu schreiben. Um eine short int-Variable anzuzeigen, setzen Sie den Buchstaben h vor eines der normalen Integer-Konvertierungszeichen: %hi, %ho oder %hx. Alternativ können Sie auch eines der Integer-Konvertierungszeichen verwenden, um short ints anzuzeigen, da sie in Integer umgewandelt werden können, wenn sie als Argumente an die printf()-Routine übergeben werden.

Der letzte Spezifizierer, der vor einer int-Variablen platziert werden kann, wird verwendet, wenn eine Integer-Variable verwendet wird, um nur positive Zahlen zu speichern. Die Deklaration

unsigned int counter;

erklärt dem Compiler, dass der Variablenzähler nur positive Werte enthalten soll. Durch die Beschränkung der Verwendung einer Integer-Variablen auf die ausschließliche Speicherung positiver Ganzzahlen wird die Genauigkeit der Integer-Variablen erweitert.

Eine vorzeichenlose int-Konstante wird gebildet, indem man den Buchstaben u (oder U) hinter die Konstante setzt, wie folgt:

0x00ffU

Sie können die Buchstaben u (oder U) und l (oder L) kombinieren, wenn Sie eine Integer-Konstante schreiben, so

20000UL

wird dem Compiler mitgeteilt, dass er die Konstante 20000 als vorzeichenlosen Long behandeln soll.

Eine Integer-Konstante, die nicht von einem der Buchstaben u, U, l oder L gefolgt wird und die zu groß ist, um in einen normal großen int zu passen, wird vom Compiler als ein unsigned int behandelt. Wenn er zu klein ist, um in einen unsigned int zu passen, behandelt der Compiler ihn als long int. Wenn er immer noch nicht in einen long int passt, macht der Compiler ihn zu einem unsigned long int. Passt er nicht hinein, behandelt der Compiler ihn als long long int, wenn er passt, und andernfalls als unsigned long long int.

Wenn man Variablen vom Typ long long int, long int, short int oder unsigned int deklariert, kann man das Schlüsselwort int weglassen. Daher hätte die vorzeichenlose Variable counter wie folgt deklariert werden können:

unsigned counter;

Sie können auch char-Variablen als vorzeichenlos deklarieren.

Der signed qualifier kann verwendet werden, um dem Compiler ausdrücklich mitzuteilen, dass eine bestimmte Variable eine vorzeichenbehaftete Größe ist. Er wird in erster Linie vor der char-Deklaration verwendet und wird erst in Kapitel 13, „Mehr über Datentypen“

Machen Sie sich keine Sorgen, wenn Ihnen die Diskussionen über diese Spezifizierer an dieser Stelle etwas esoterisch erscheinen. In späteren Abschnitten dieses Buches werden viele dieser verschiedenen Typen anhand von konkreten Programmbeispielen erläutert. Kapitel 13 geht detaillierter auf Datentypen und Konvertierungen ein.

Tabelle 3.1 fasst die grundlegenden Datentypen und Qualifier zusammen.

Tabelle 3.1 Grunddatentypen