Zu den Grundlagen der C Programmierung gehören auch die Kenntnis der einzelnen Datentypen. Datentypen sind, wie der Name schon vermuten lässt, Arten von Variablen, in denen Sie Daten speichern können, um zu einem späteren Zeitpunkt wieder darauf zurückzugreifen.C C++ C/C++ Datentypen Variablen int long short char float double unsigned signed Datentypen und Variablen - int long short char float double unsigned signed Kapitel 8: Datentypen und Variablen

8.8. Der Datentyp char            zurück  Ein Kapitel höher  zum Inhaltsverzeichnis

Der Datentyp char kann auf zwei logisch völlig unterschiedliche Arten verwendet werden. Zum einen dient er der Darstellung von einzelnen Zeichen wie 'a', 'A', 'b', 'B', '5', '7', '§' usw. für Tastatureingabe und Bildschirmausgabe. Zum anderen kann char genutzt werden, um kleine Ganzzahlen zu verarbeiten. Wobei gesagt werden muss, dass dafür der Wertebereich relativ klein ist. Hier die Übersicht dazu:

Name Größe Wertebereich Formatzeichen
char 1 Byte -128
+127
%c

Tabelle 8.3: Der Datentyp char

char ist auch der kleinste darstellbare elementare Datentyp in der Programmiersprache C.

An dieser Stelle will ich zum besseren Verständnis etwas weiter ausholen. Der Computer ist eigentlich dumm. Er kennt nichts anderes als die Zustände 0 für "aus" und 1 für "ein". Dies entspricht etwa einem Lichtschalter, den Sie ein- oder ausschalten können. Im Fall von char wären dies acht Lichtschalter. Zuerst ein kleiner Überblick über die Größe der Datentypen:

Größe von char           1 Byte  =  8 Bit
Größe von short          2 Byte  = 16 Bit
Größe von int     2 oder 4 Byte  = 16 Bit oder 32 Bit
Größe von long           4 Byte  = 32 Bit
Größe von float          4 Byte  = 32 Bit
Größe von double         8 Byte  = 64 Bit
Größe von long double   10 Byte  = 80 Bit

Abbildung 8.5: Einzelne Bits der Datentypen im Überblick

Abbildung 8.5: Einzelne Bits der Datentypen im Überblick

Betrachten Sie den Datentyp char, der ja aus acht einzelnen Bits besteht. Acht Bits sind in der Informatik ein Byte:

Abbildung 8.6: Ein Byte in der Informatik (Datentyp char)

Abbildung 8.6: Ein Byte in der Informatik (Datentyp char)

Jedes dieser acht Bits, die aus der Speichergröße von einem Byte entstehen, kann einen bestimmten Wert darstellen:

Abbildung 8.7: Diese Zahlen ergeben sich durch die Potenzen von 2

Abbildung 8.7: Diese Zahlen ergeben sich durch die Potenzen von 2

Der PC kann doch nur zwei Zahlen darstellen. Woher kommen dann diese Werte? Sie werden aus der Potenz von 2 berechnet (27+26+25+24+23+22+21+20). Würden Sie jetzt hier Bit 0 und Bit 1 auf 1 setzen, also Licht an, würde der Wert 3 dargestellt. Dieser errechnet sich ebenfalls wieder aus den Potenzen:

0*27+0*26+0*25+0*24+0*23+0*22+1*21+1*20 = 3 

Ein Beispiel:

Abbildung 8.8: Dualdarstellung des dezimalen Werts 66

Abbildung 8.8: Dualdarstellung des dezimalen Werts 66

Der Dezimalwert dieser Zusammensetzung der einzelnen Bits beträgt 66 (0*27+1*26+0*25+0*24+0*23+0*22+1*21+0*20 = 66). Es müssen nur die einzelnen Bits zusammengezählt werden, die gesetzt (also 1) sind. Wenn Sie jetzt die ASCII-Code-Tabelle am Ende des Buchs betrachten und unter dem dezimalen Wert 66 nachsehen, stellen Sie fest, dass 66 für das große 'B' steht. Es geht nämlich hier bei char nicht um den int-Wert, sondern um das Zeichen, das diesem dezimalen Wert in der ASCII-Tabelle entspricht.

Die ASCII-Code-Tabelle ist eine Tabelle, an die sich alle Programmierer der Welt halten müssen. Sie enthält alle Zeichen, die der Computer darstellen kann.

Nach diesem kleinen Ausflug ins Dualsystem zurück zum Thema dieses Kapitels, dem Datentyp char. Hier ein kleines Listing:

#include <stdio.h>

int main()
{
   char a = 'A';
   char b = 65;
   int c = 65;
   int d;

   printf("a = %c\n",a);
   printf("b = %c\n",b);    /*Überrascht?*/
   printf("c = %c\n",c);    /*Nochmals :) */

   d = a + b + c;           /*Rechenbeispiel*/
   printf("d = %d\n",d);

   d = 'a' + 'A';
   printf("d = %d\n",d);

   printf("char a = %c und %d\n",a,a);
   printf("char b = %c und %d\n",b,b);
   printf("int c = %c und %d\n",c,c);
   return 0;
}

Der Programmablauf sieht etwa folgendermaßen aus:

Abbildung 8.9: Programm bei der Ausführung unter Linux
Abbildung 8.9: Programm bei der Ausführung unter Linux

Jetzt zur Zeile:

char a = 'A'; 

Wenn Sie char ein Zeichen zuweisen wollen, muss es zwischen zwei einzelnen Hochkommata stehen ('A'). Folgende Varianten sind nicht möglich bzw. falsch:

/*falsch, in doppelte Hochkommata == String*/
char a = "A";

/*falsch, Variablenzuweisung*/
char a = A;

/* Schlechter Stil, da nicht gleich durchschaubar, ob der
 * Programmierer hier den ASCII-Buchstaben oder den dezimalen
 * Wert verwenden will
 */
char b = 65;

Hier auch gleich die andere Möglichkeit, char einen Wert zuzuweisen. Für den PC ist der Wert 65 und das Zeichen 'A' identisch. Beide haben dieselbe Bitdarstellung:

Abbildung 8.10: Bitdarstellung des Dezimalwerts 65 und des Zeichens 'A'

Abbildung 8.10: Bitdarstellung des Dezimalwerts 65 und des Zeichens 'A'

Dies bestätigt auch die Ausgabe im Programm:

printf("a = %c\n",a);
printf("b = %c\n",b);

Auch wenn es hier so aussieht, in C gibt es keinen Datentyp, mit dem Sie echte Zeichen wie 'A' 'B' oder 'C' speichern können. Daher stehen diese Zeichen auch zwischen einzelnen Anführungszeichen. Sie geben zwar Folgendes an:

char a = 'A'; 

aber nach der Übersetzung des Compilers sieht dies so aus:

char a = 65; 

Verwenden Sie jetzt im Programm das Formatierungszeichen %c, wird der Wert 65 anhand der ASCII-Code-Tabelle kodiert. Wird hierbei das Formatierungszeichen %d verwendet, würde dieser Wert nicht kodiert und in seiner tatsächlichen Form ausgegeben, wobei "tatsächliche Form" natürlich die rein optische meint. In Wirklichkeit wäre die tatsächliche Form eine Zahlenkolonne von Einsen und Nullen. Für den PC gelten weiterhin nur Bits und Bytes. Und wie Sie gesehen haben, funktioniert das analog auch mit dem Datentyp int.

Achtung
 

Auch wenn Sie char oder unsigned char für kleine Ganzzahlwerte verwenden könnten, ist von dieser Möglichkeit abzuraten. Dies vor allem, weil in C nicht festgelegt ist, ob dieser Datentyp mit oder ohne Vorzeichen interpretiert wird. Es könnte ähnlich wie bei int auf verschiedenen Systemen zu unterschiedlichem Verhalten oder gar Fehlern führen (siehe Abschnitt 8.1 zu int).

8.9. Nationale contra internationale Zeichensätze            zurück  Ein Kapitel tiefer  Ein Kapitel höher  zum Inhaltsverzeichnis

Der ASCII-Zeichensatz (American Standard Code for Information Interchange) wurde von US-amerikanischen Ingenieuren entwickelt. Zur damaligen Zeit wurde als achtes Bit das Paritätsbit benutzt, womit nur noch sieben Bits zur Verfügung standen; also gab es Platz für 128 Zeichen und Sonderzeichen.

Nun fehlte der Platz für westeuropäische und slawische Zeichen (von der japanischen mit über 40.000 Zeichen und der kyrillischen Schrift ganz zu schweigen). Man beschränkte sich also auf die Zeichen, die im Englischen benötigt wurden.

Als die Europäer mit ihren landestypischen Zeichen ebenfalls in die ASCII-Tabelle aufgenommen werden wollten, war es schon zu spät. Wie Sie an der ASCII-Code-Tabelle sehen können, befinden sich unter den 128 Zeichen, die in 7 Bits Platz haben, keine Umlaute wie zum Beispiel "äöüßÄÖÜß" oder landestypische Zeichen anderer europäischer Länder wie etwa französische.

Jetzt war die ISO (International Organisation for Standards) gefragt. Der ASCII-Zeichensatz wurde auf 8 Bits erweitert und unter der Bezeichnung "ISO-8859-1, ISO-8859-2 usw." etabliert. Der westeuropäische Standard ist in der "ISO-8859-1" erfasst. Damit lassen sich folgende Zeichen darstellen:

#include <stdio.h>

int main()
{
   int i;
   for(i=0; i < 254; i++)
      {
         if(i==26)   /* ESC ignorieren */
            continue;
         printf(" |%d : %c| ",i,i);
      }
   return 0;
}

Die deutschen Sonderzeichen in oktaler Form können auch folgendermaßen ausgegeben werden:

#include <stdio.h>

int main()
{
   int i;
   printf("R\204tsel, \231l, \232berfall\n");
   printf("Umlaute oktal : \204\216\224\231\201\232\341\n");
   return 0;
}

Das Problem mit den deutschen Sonderzeichen unter der Windows-Konsole ist, dass diese nicht den gewöhnlichen Windows-Zeichensatz verwendet, sondern einen OEM-Zeichensatz. Deshalb muss in diesem Fall ein Umweg gegangen werden. Mit Linux haben Sie dieses Problem nicht.

Mit char können Sie somit Zeichensätze mit einem Speicherbedarf von 8 Bits darstellen. Für Unicode-Zeichensätze sollte der Datentyp wchar_t eingesetzt werden. Er hat einen Speicherbedarf von 16 Bits.

8.10. Vorzeichenlos und vorzeichenbehaftet            zurück  Ein Kapitel tiefer  Ein Kapitel höher  zum Inhaltsverzeichnis

Mit dem Schlüsselwort unsigned weisen Sie den Compiler an, dass er einen Datentyp vorzeichenlos behandeln soll. Dadurch erhöht sich auch der Wertebereich der positiven Zahlen. Mit dem Schlüsselwort signed bewirken Sie genau das Gegenteil. signed ist bei allen Datentypen voreingestellt. Das bedeutet, dass folgende Schreibweisen die gleiche Bedeutung haben:

int a;
signed int a;

Am besten sehen Sie sich dazu die Tabelle an, auf der sich alle Datentypen befinden, die Sie bisher kennen gelernt haben.

Name Größe Wertebereich
char, signed char 1 Byte = 8 Bit -128…+127
unsigned char 1 Byte = 8 Bit 0…255
short, signed short 2 Byte = 16 Bit -32768…+32767
unsigned short 2 Byte = 16 Bit 0…65535
int, signed int 4 Byte = 32 Bit -2147483648…+2147483648
unsigned int 4 Byte = 32 Bit 0…4294967295
long, signed long 4 Byte = 32 Bit -2147483648…+2147483648
unsigned long 4 Byte = 32 Bit 0…4294967295
float 4 Byte = 32 Bit 3.4*10-38…3.4*1038
double 8 Byte = 64 Bit 1.7*10-308…1.7*10308
long double 10 Byte = 80 Bit 3.4*10-4932…3.4*104932

Tabelle 8.6: Übersicht aller Standard-Datentypen in C

Dazu nochmals char als Beispiel. Manch einer wird sich vorhin gedacht haben: "Warum kann ich mit char nur Werte zwischen -128 und 127 darstellen?"

Denn, wenn alle Bits gesetzt sind, und Sie nachrechnen, ist das Ergebnis der Summe 255. Doch es müssen ja auch negative Werte dargestellt werden, etwa -100. Wenn das Schlüsselwort unsigned vor einen Datentyp gestellt wird, sind keine negativen Zahlen mehr möglich. Somit verdoppelt sich aber der positive Wert der Zahl. Sollten Sie z.B. zwei Zahlen subtrahieren und es kommt ein negatives Ergebnis heraus, und es wurde vor dem Datentyp des Ergebnisses das Schlüsselwort unsigned gesetzt, so wird das Minus der negativen Zahl ignoriert und es wird eine positive Zahl daraus.

8.11. Limits für Ganzzahl- und Gleitpunktdatentypen            zurück  Ein Kapitel tiefer  Ein Kapitel höher  zum Inhaltsverzeichnis

Jetzt haben Sie eine Menge über Datentypen und ihre Eigenschaften erfahren. Häufig hieß es jedoch, auf bestimmten Systemen hat Datentyp x die Größe y. Wenn Sie jetzt erfahren wollen, welchen maximalen oder minimalen Wert der Datentyp int z.B. auf Ihrem System besitzt, können Sie die Konstanten in den Standard-Headerdateien <limits.h> und <float.h> abfragen bzw. ausgeben. Mit folgendem Listing ist es möglich, alle Limits des Datentyps int auf Ihrem System abzufragen:

#include <stdio.h>
#include <limits.h>

int main()
{
   printf("int-Wert mindestens: %d\n",INT_MIN);
   printf("int-Wert maximal   : %d\n",INT_MAX);
   printf("unsigned int max.  : %u\n",UINT_MAX);
   printf("int benötigt %d Byte (%d Bit) Speicher\n",
           sizeof(int),sizeof(int)*CHAR_BIT);
   return 0;
}

Genauso wie in diesem Beispiel können Sie auch die anderen Limiteigenschaften der Datentypen abfragen. Vorausgesetzt, Sie binden die Headerdatei <limits.h> mit ein. Hierzu die Tabelle der Limits für ganzzahlige Datentypen in der Headerdatei <limits.h>:

Konstante Mindestwert Erklärung
CHAR_BIT 8 Bitzahl für ein Byte
SCHAR_MIN -127 min. signed char
SCHAR_MAX +127 max. signed char
UCHAR_MAX 255 max. unsigned char
CHAR_MIN SCHAR_MIN oder 0 min. char
CHAR_MAX SCHAR_MAX oder UCHAR_MAX max. char
MB_LEN_MAX 1 max. Byte für ein Viel-Bytezeichen
SHRT_MIN -32767 min. short int
SHRT_MAX +32767 max short int
USHRT_MAX 65535 max. unsigned short
INT_MIN -32767(32Bit: -2147483647) min. int
INT_MAX +32767(32Bit: +2147483647) max. int
UINT_MAX 65535(32Bit: 4294967295) max. unsigned int
LONG_MIN -2147483647 min. long int
LONG_MAX +2147483647 max. long int
ULONG_MAX 4294967295 max. unsigned long int

Tabelle 8.7: Limit-Konstanten für ganzzahlige Datentypen in <limits.h>

Benötigen Sie hingegen Limitwerte für Gleitpunktzahlen, gibt die Headerdatei <float.h> Auskunft. Darin finden Sie u.a. Konstanten mit allen Limits und Eigenschaften, die für Gleitpunktdatentypen entscheidend sind. Das folgende Listing gibt alle Limits und Eigenschaften für den Datentyp float auf Ihrem System aus:

#include <stdio.h>
#include <float.h>
#include <limits.h> //für CHAR_BIT

int main()
{
   printf("Limits und Eigenschaften des float-Wertes\n\n");
   printf("float benötigt %d Bytes (%d Bit) an Speicherplatz\n",
           sizeof(float),sizeof(float)*CHAR_BIT);
   printf("Basis für Exponentendarstellung: %d\n",FLT_RADIX);
   printf("Anzahl der Mantissenstellen  : %d\n",FLT_MANT_DIG);
   printf("Anzahl sign. Dezimalziffern  : %d\n",FLT_DIG);
   printf("Kleinst. neg. FLT_RADIX-Exponent: %d\n",FLT_MIN_EXP);
   printf("Kleinst. neg. Zehnerexponent : %d\n",FLT_MIN_10_EXP);
   printf("Größter FLT_RADIX-Exponent   : %d\n",FLT_MAX_EXP);
   printf("Größter Zehnerexponent       : %d\n",FLT_MAX_10_EXP);
   printf("Größter endlicher float-Wert   : %f\n",FLT_MAX);
   printf("Kleinster endlicher float-Wert : %f\n",FLT_MIN);
   return 0;
}

Auch hierzu eine Tabelle mit den Limits und Eigenschaften von Gleitpunktdatentypen, welche in der Headerdatei <float.h> deklariert sind:

Konstante Bedeutung
FLT_RADIX Basis für Exponentendarstellung
FLT_MANT_DIG Anzahl Mantissenstellen (float)
DBL_MANT_DIG Anzahl Mantissenstellen (double)
LDBL_MANT_DIG Anzahl Mantissenstellen (long double)
FLT_DIG Genauigkeit in Dezimalziffern (float)
DBL_DIG Genauigkeit in Dezimalziffern (double)
LDBL_DIG Genauigkeit in Dezimalziffern (long double)
FLT_MIN_EXP Minimalster negativer FLT_RADIX-Exponent (float)
DBL_MIN_EXP Minimalster negativer FLT_RADIX-Exponent (double)
LDBL_MIN_EXP Minimalster negativer FLT_RADIX-Exponent (long double)
FLT_MIN_10_EXP Minimalster negativer Zehnerexponent (float)
DBL_MIN_10_EXP Minimalster negativer Zehnerexponent (double)
LDBL_MIN_10_EXP Minimalster negativer Zehnerexponent (long double)
FLT_MAX_EXP Maximaler FLT_RADIX-Exponent (float)
DBL_MAX_EXP Maximaler FLT_RADIX-Exponent (double)
LDBL_MAX_EXP Maximaler FLT_RADIX-Exponent (long double)
FLT_MAX_10_EXP Maximaler Zehnerexponent (float)
DBL_MAX_10_EXP Maximaler Zehnerexponent (double)
LDBL_MAX_10_EXP Maximaler Zehnerexponent (long double)
FLT_MAX Maximaler Gleitpunktwert (float)
DBL_MAX Maximaler Gleitpunktwert (double)
LDBL_MAX Maximaler Gleitpunktwert (long double)
FLT_EPSILON Kleinster float-Wert x für den 1.0 + x ungleich 1.0 gilt
DBL_EPSILON Kleinster double-Wert x für den 1.0 + x ungleich 1.0 gilt
LDBL_EPSILON Kleinster long double-Wert x für den 1.0 + x ungleich 1.0 gilt
FLT_MIN Minimalster normalisierter Gleitpunktwert (float)
DBL_MIN Minimalster normalisierter Gleitpunktwert (double)
LDBL_MIN Minimalster normalisierter Gleitpunktwert (long double)

Tabelle 8.8: Limit-Konstanten für Gleitpunkt-Datentypen in <float.h>

Natürlich gilt auch bei der Verwendung der Konstanten, welche sich in der Headerdatei befinden, dass die entsprechende Headerdatei mit eingebunden wird.

8.12. Konstanten            zurück  Ein Kapitel tiefer  Ein Kapitel höher  zum Inhaltsverzeichnis

Eine Konstante ist entweder eine ganzzahlige Konstante, eine Gleitpunktkonstante, Zeichenkonstante oder ein String-Literal. Jede Konstante besteht aus einem Typ, der sich aus dem Wert und seiner Schreibweise ergibt.

8.12.1 Ganzzahlkonstanten
Ganzzahlige Konstanten können als Dezimalzahl, als Oktalzahl oder als Hexadezimalzahl dargestellt werden. Die dezimale Konstante kann durch folgende Datentypen dargestellt werden:

int, unsigned long, long

Oktale und hexadezimale Konstanten lassen sich mit folgenden Datentypen darstellen:

int, unsigned int, long, unsigned long    

Der Typ der Konstante lässt sich übrigens auch mit dem Suffix L oder l für long und u oder U für unsigned beeinflussen.

Einige Beispiele ganzzahliger Konstanten:

dezimal hexadezimal oktal Typ
30 0x1e 036 int
30U 0x1eu 036U unsigned int
30L 0x1eL 036l long
30ul 0x1EUL 036UL unsigned long

Tabelle 8.9: Beispiele ganzzahliger Konstanten

8.12.2 Gleitpunktkonstanten
Eine Gleitpunktkonstante ist eine Folge von Dezimalziffern mit einem Gleitpunkt. Gleitpunktkonstanten müssen stets mit einem Gleitpunkt oder der Angabe von e oder E gekennzeichnet werden. Wird kein Suffix angegeben, ist die Konstante vom Typ double. Mit dem Suffix f oder F ist der Typ der Konstante float, und mit dem Suffix l oder L wird daraus ein long double.

Auch hierzu einige Beispiele:

11. .11e2 11e0 11.0
0.007 0.7e-2 .7E-2 7E-3

Tabelle 8.10: Beispiele von Gleitpunktkonstanten

8.12.3 Zeichenkonstanten
Zeichenkonstanten bestehen aus einem Zeichen, welches zwischen zwei einfachen Hochkommata eingeschlossen wird. Zeichenkonstanten sind intern vom Typ int und werden durch entsprechenden Zeichencode (ASCII-Code) dargestellt. Einige Beispiele von Zeichenkonstanten:

'a', 'b', '\t', '\n', 'x' 

Wollen Sie eine Zeichenkonstante vom Typ wchar_t verwenden, müssen Sie das Präfix L voranstellen:

L'a', L'b', L'\t', L'\n', L'x'

In der Praxis werden Sie höchstwahrscheinlich nie mit wchar_t zu tun haben, aber es sollte hier dennoch erwähnt werden.

8.12.4 String-Literale (Stringkonstante)
Ein String-Literal ist ein char-Array, welches mit dem schließenden Stringende-Zeichen \0 gespeichert wird. Außerdem werden String-Literale zwischen zwei doppelte Hochkommata gestellt. Beispiele:

"Hallo Welt", "Hallo\nWelt\n"

Sofern Sie auch hierbei so genannte Wide-String-Literale definieren wollen, muss auch hier das Präfix L vorangestellt werden.

L"Hallo Welt", L"Hallo\nWelt\n"   

Mehr zu den Strings im Allgemeinen erfahren Sie in Kapitel 14, Arrays.

8.13. Umwandlungsvorgaben für formatierte Ein-/Ausgabe            zurück  Ein Kapitel höher  zum Inhaltsverzeichnis

Sie haben oben für Datentypen auch die Umwandlungsvorgaben, also Formatzeichen, kennen gelernt. Es lässt sich damit aber noch eine Menge mehr anstellen. Die Formatierungszeichen (oder auch Formatierungsanweisung genannt) beginnen immer - wie schon bei scanf() und printf() - mit dem Zeichen % und beziehen sich dann auch auf das oder die nachfolgenden Argumente. Mit

scanf("%d",&a);

wird beispielsweise auf die Eingabe eines Integerwerts gewartet. Dies erkennen Sie am Formatierungszeichen %d. Folglich wird durch

%c 

ein char-Zeichen anhand der ASCII-Code-Tabelle in einen Buchstaben umgewandelt (genauer kodiert). Aber außer den bereits erwähnten Umwandlungszeichen können noch weitere Umwandlungsvorgaben festgelegt werden. Bei der formatierten Ausgabe mit Funktionen, wie z.B. printf(), fprintf(), vprintf()und sprintf(), haben Sie noch folgende Möglichkeiten:

% F W G L U  

Die Bedeutung der einzelnen Buchstaben ist:

Die Formatierungszeichen sind die Zeichen eines bestimmten Typs, die Sie ausgeben können. Hier ist die Liste. Einige wurden bereits verwendet:

Formatierungszeichen Es wird ausgegeben (eine) …
%d, %i ... vorzeichenbehaftete ganze Dezimalzahl.
%o ... vorzeichenlose ganze Oktalzahl.
%u ... vorzeichenlose ganze Dezimalzahl.
%x, %X ... vorzeichenlose ganze Hexzahl (a,b,c,d,e,f) bei x; (A,B,C,D,E,F) bei X
%f ... Gleitpunktzahl in Form von ddd.dddddd
%e, %E ... Gleitpunktzahl in Form von d.ddde+-dd bzw. d.dddE+-dd. Der Exponent enthält mindestens 2 Ziffern.
%g, %G ... float ohne Ausgabe der nachfolgenden Nullen
%c ... Form von einem Zeichen (unsigned char)
%s ... Form einer Zeichenkette
%p Ausgabe eines Zeigerwertes
%n Keine Ausgabe. Dieses Argument ist ein Zeiger auf eine Ganzzahl.
%% ... das Zeichen %

Tabelle 8.11: Typenbezeichner von Formatanweisungen

Beim Einlesen eines Zeichens, eines numerischen Werts oder einer Zeichenkette gelten bei der formatierten Eingabe mit Funktionen wie etwa scanf(), sscanf(), fscanf() dieselben Umwandlungszeichen wie bei printf(). Hierbei können Sie aber auch noch eine Suchmengenkonvertierung verwenden:

Umwandlungszeichen Es wird eingelesen ...
%[bezeichner] … bis ein Zeichen eingegeben wurde, welches nicht in der Liste bezeichner vorkommt.
%[^bezeichner] … bis ein Zeichen eingegeben wurde, das in der Liste bezeichner vorkommt.

Tabelle 8.12: Suchmengenkonvertierung mit scanf()

Diese Suchmengenkonvertierung kann durch Zeichen des Formatierungstyps s (s = String, Zeichenkette) ersetzt werden. Dabei wird die Menge von Zeichen eingeschlossen, welche sich zwischen den Klammern befindet. Beispiel:

#include <stdio.h>

int main()
{
   char str[20];
   printf("Bitte geben Sie nur Zahlen ein: ");
   scanf("%[0-9]", str);

   printf("%s\n",str);
   return 0;
}

Abbildung 8.11: Suchmengenkonvertierung mit scanf()
Abbildung 8.11: Suchmengenkonvertierung mit scanf()

In diesem Beispiel werden Sie aufgefordert nur Zahlen einzugeben. scanf() ließt so lange Zahlen ein, bis das erste Zeichen nicht zwischen 0 bis 9 ist. Beachten Sie bitte, dass es sich hierbei um keine reellen Zahlen handelt, sondern um einen String. Wünschen Sie eine reelle Zahl, müssen Sie den String mit einer entsprechenden Funktion konvertieren. Mehr dazu später beim Thema Strings.

Ist das erste Zeichen der Suchmenge ein Caret (^), wird die Suchmenge invertiert, sodass alle ASCII-Zeichen zulässig sind, außer denen, welche in den Klammern angegeben sind. Auch hierzu ein Beispiel:

#include <stdio.h>

int main()
{
   char str[20];
   printf("Eingabe machen (keine Buchstaben wie x,y und z): ");
   scanf("%19[^xyz]", str);

   printf("%s\n",str);
   return 0;
}

Hierbei ließt scanf() so lange ein, bis es auf das Zeichen 'x' 'y' oder 'z' trifft. Zusätzlich wurde hier festgelegt, dass scanf() nach mehr als 19 Zeichen ebenfalls abbricht (aus Sicherheitsgründen sollten Sie scanf() in der Praxis immer mit einer Längenangabe verwenden). Weitere Beispiele:

%[A-Z]    //alle Grossbuchstaben von A bis Z
%[a-z]    //alle Kleinbuchstaben von a bis z
//Alle Gross- Kleinbuchstaben von A bis F (Hexadezimalzahlen)
%[a-fA-F]

Wenn Sie wie in diesen Beispielen den Bindestrich verwenden, müssen Sie folgende Regeln beachten:

Weiter mit den Formatierungszeichen, welche ausschließlich für die formatierte Ausgabe, wie mit printf(), fprintf(), sprintf() und vprintf(), gedacht sind. Folgende Flags stehen dafür zur Verfügung:

Flag Bedeutung
- Links bündig justieren
+ Ausgabe des Vorzeichens '+' oder '-'
Leerzeichen Ist ein Argument kein Vorzeichen, wird ein Leerzeichen mit ausgegeben.
0 Bei numerischer Ausgabe wird mit Nullen bis zur angegebenen Weite aufgefüllt.
# Bei o bzw. x oder X wird mit vorangestellter 0 bzw. 0x ausgegeben. Bei e, E oder f wird der Wert mit einem Dezimalpunkt ausgegeben, auch wenn keine Nachkommastelle existiert.

Tabelle 8.13: Flags für die Formatanweisung

Die Flags müssen nach dem %-Zeichen stehen, und falls es sinnvoll ist, können mehrere Flags gleichzeitig verwendet werden. Als Nächstes die Ausgabe der Weite. Folgende zwei Angaben lassen sich dazu verwenden:

Angaben Bedeutung
n Es werden mindestens n Stellen ausgegeben, auch wenn der Wert weniger als n Stellen besitzt.
* Wert des nächsten Arguments (ganzzahlig) legt die Weite fest. Bei negativem Wert wird linksbündig justiert.

Tabelle 8.14: Formatangaben zur Ausgabe der Weite

Folgendes Programm soll die Ausgabe der Weite demonstrieren:

#include <stdio.h>

int main()
{
   int i=10;
   printf("%5d\n",i);
   printf("%*d\n",i,i);
   return 0;
}

Falls Sie eine nicht vorhandene oder zu kleine Weitenangabe vornehmen, bewirkt dies nicht, dass die Zahlen beschnitten werden bzw. mehr Zeichen enthalten. Beispiel:

printf("%2d\n",100);
printf("%4d\n",100);

In beiden Fällen wird die Zahl 100 ausgegeben, egal, welche Längenangabe getroffen wird. Beim formatierten Einlesen gilt als Weitenangabe:

scanf("%2d\n",&zahl); 

Falls Sie jetzt nach dieser scanf()-Eingabe-Aufforderung mehr als zwei Ziffern eingeben, z.B. 100, so wird in diesem Fall die letzte 0 nicht mit eingelesen, und der Wert der Variable zahl ist 10. Jetzt zur Genauigkeitsangabe der formatierten Ausgabe. Der genauen Schreibweise geht ein Punkt voran:

printf("%.2f\n",3.143234); 

Hiermit wird die Gleitpunktzahl "3.143234" ausgegeben als "3.14". Das heißt aber nicht, dass sich der Wert der Zahl verändert hat, sondern dies bezieht sich nur auf die formatierte Ausgabe. Die Zahl wird also nicht auf- oder abgerundet. So bewirkt z.B. die Ausgabe von

printf("%.2d\n",1000); 

nicht, dass 10 ausgegeben wird. In diesem Fall wird dennoch die Zahl 1000 ausgegeben. Hingegen wird bei Strings dieser Bereich wiederum beschnitten. Zur Verdeutlichung ein weiteres Beispiel:

#include <stdio.h>

int main ()
{
   char text[]="Tiefstand";

   printf("|01234567890123456789|\n");
   printf("|%s|\n",text);
   printf("|%20s|\n",text);
   printf("|%-20s|\n",text);
   printf("|%20s|\n",text+4);
   printf("|%20.4s|\n",text);
   printf("|%-20.4s|\n",text);
   printf("|%-20s|\n",text+4);
   return 0;
}

Abbildung 8.12: Formatierte Ausgabe mit Angabe der Weite
Abbildung 8.12: Formatierte Ausgabe mit Angabe der Weite

Zum Schluss sind jetzt noch die einzelnen Längenangaben und ihre jeweiligen Auswirkungen vorzustellen. Im Fachjargon spricht man auch von einer Argumenttyp-Modifikation:

Modifikation Auswirkung
h Die Umwandlungszeichen d, i, o, u, x, X werden als short-Wert behandelt.
l Die Umwandlungszeichen d, i, o, u, x, X werden als long-Wert behandelt.
L Die Umwandlungszeichen e, E, f, g, G werden als long double-Wert behandelt.

Tabelle 8.15: Argumenttyp-Modifikationen

Weiter mit Kapitel 9: Operatoren            zum Inhaltsverzeichnis