5. Einfache Ein- und Ausgabe in C

Ein Programm empfängt einen Strom (englisch: stream) von eingegebenen Daten, verarbeitet diese und gibt dann das Ergebnis als Strom von Daten wieder aus. Unter einem Datenstrom versteht man eine Folge von Zeichen. Für einen Datenstrom gibt es verschiedene Standardkanäle, die bereits definiert sind.

Standardkanal

Datenstrom

Standardeingabe (Tastatur)

stdin

Standardausgabe (Bildschirm)

stdout

Standardfehlerausgabe (Bildschirm)

stderr

Standarddrucker (parallele Schnittstelle)

stdprn

Standardzusatzgerät (serielle Schnittstelle)

stdaux


Diese Standardkanäle können mit Hilfe einiger Funktionen angesprochen werden. Um diese Funktionen sowie deren Verwendung für Standardein- und ausgaben soll es in diesem Kapitel gehen.

Die Standardeingabe geschieht in der Regel über die Tastatur, die Standardausgabe auf dem Bildschirm. Es gibt die Möglichkeit, Ein- und Ausgabe auf Dateien umzulenken, aber darauf wird hier nicht eingegangen.

Die Unterscheidung zwischen der Standardausgabe und der Standardfehlerausgabe dient dem Zweck, zwischen normalen Ausgaben und Fehlermeldungen unterscheiden zu können. Beispielsweise könnten so alle normalen Meldungen auf dem Bildschirm und die Fehlermeldungen in eine Protokolldatei ausgegeben werden.

5.1. Datenausgabe auf den Bildschirm

Mit Hilfe des Bildschirms teilt ein Programm die Ergebnisse von Befehlen dem Benutzer mit. Dabei können konstante und variable Texte und Zahlen formatiert ausgegeben werden. Die Standardfunktion für eine Bildschirmausgabe ist die printf-Funktion. Dabei steht printf für "print formatted". Um die Funktion verwenden zu können, muss die Headerdatei stdio.h mittels #include <stdio.h> eingebunden werden.

Die komplette Syntax der printf-Funktion lautet:
int printf(const char *format [,argument_1 ... ,argument_n]);

Dabei haben die einzelnen Wörter die folgenden Bedeutungen:

int

Der Datentyp vor dem Funktionsnamen gibt an, was die Funktion als Ergebnis zurückgibt. In diesem Fall ist es eine ganze Zahl (int), die angibt, wieviele Zeichen insgesamt ausgegeben wurden. Im Falle eines Fehlers ist das Ergebnis gleich dem Wert EOF.

printf

der eigentliche Funktionsname

( ... )

Innerhalb dieser runden Klammern werden der Funktion die Parameter übergeben.

const char *format

Der erste Parameter ist eine Zeichenkette, d.h. eine Folge von Zeichen, die in Anführungsstrichen stehen. In dieser Zeichenkette stehen die Formatierungen für die auszugebenden Daten. Über die Formatierungsangaben wird auch die Anzahl der auszugebenden Daten festgelegt. Die verschiedenen Formatierungsmöglichkeiten sind in den nächsten Tabellen aufgeführt. Mehr zu Zeichenketten finden Sie im Kapitel Strukturierte Datentypen.

argument

Nach der Formatierungsangabe folgen die Variablennamen, deren Inhalte auf dem Bildschirm ausgegeben werden sollen, jeweils getrennt mit einem Komma. Die Anzahl der Argumente muss mit der Anzahl der Formatierungsanweisungen übereinstimmen.


Die Formatierungszeichenkette beinhaltet zum einen "normale Zeichen", die direkt auf dem Bildschirm ausgegeben werden, und zum anderen die Formatierungsanweisungen. Eine Formatierungsanweisung hat folgenden Aufbau:
%[Flags][Breite][.Präzision][F|N|hh|h|l|ll|L]Typ

Jede Formatierungsanweisung beginnt mit einem Prozentzeichen. Auf dieses Zeichen folgen:

[Flags]

Eine (optionale) Zeichenfolge, über die numerische Vorzeichen, Dezimalpunkte, führende und folgende Nullen, oktale und hexadezimale Präfixe sowie links- und rechtsbündige Ausgabe festgelegt werden.

[Breite]

Eine (optionale) Angabe über die minimal auszugebende Zeichenzahl. Notfalls wird mit Leerzeichen oder Nullen aufgefüllt.

[.Präzision]

Eine (optionale) Angabe, wieviele Zeichen maximal ausgegeben werden (Zeichenketten), die Minimalzahl von Ziffern (ganze Zahlen) bzw. die maximale Anzahl der Nachkommastellen (Fließkommazahlen).

[F|N|hh|h|l|ll|L]

Eine (optionale) Angabe der Größe des Parameters. Genauere Angaben sind in der nächsten Tabelle enthalten.

Typ

Die Angabe des Typs der auszugebenen Variable (siehe nächste Tabelle). Diese Angabe muss auf jeden Fall gemacht werden!


Die folgende Tabelle gibt alle möglichen Typen an. Dabei wird erst einmal davon ausgegangen, dass außer der Größenangabe keine optionalen Angaben gemacht werden, d.h. keine Flags, Breite und keine Präzision.

Typ

optionale
Größen-
angabe

Datentyp des
Parameters

Ausgabe

erlaubte
Flags

d i1

<keine>
hh3
h1
l
ll3

int
char 
short 
long
long long3

dezimaler Integer

- +
Leerzeichen

u

<keine>
hh3
h1
l
ll3

unsigned int
unsigned char 
unsigned short 
unsigned long
unsigned long long3

dezimaler Integer
(nur positive Zahlen)

- +
Leerzeichen

o

<keine>
hh3
h1
l
ll3

unsigned int
unsigned char 
unsigned short 
unsigned long
unsigned long long3

oktaler Integer
(nur positive Zahlen)

- + #
Leerzeichen

x X

<keine>
hh3
h1
l
ll3

unsigned int
unsigned char 
unsigned short 
unsigned long
unsigned long long3

hexadezimaler Integer
(nur positive Zahlen)
bei Typ x: mit Buchstaben a...f
bei Typ X: mit Buchstaben A...F

- + #
Leerzeichen

f F4

<keine>
L

float, double
long double

dezimale Fließkommazahl
vorzeichenbehafteter Wert der Form [-]d.dddddd, die Anzahl der Nachkommastellen kann durch die Angabe .Präzision festgelegt werden.
Ausgabebeispiele: -.900000, 3.141500

- + #
Leerzeichen

e E

<keine>
L

float, double
long double

dezimale Fließkommazahl
vorzeichenbehafteter Wert der Form [-]d.dddddd e [+|-]dd (Exponentendarstellung), es steht grundsätzlich eine Ziffer vor dem Dezimalpunkt, die Anzahl der Nachkommastellen kann durch die Angabe .Präzision festgelegt werden, der Exponent hat immer zwei Ziffern (notfalls mit führender Null).
Ausgabebeispiele: -1.900000e+00, 2.550000e-03

- + #
Leerzeichen

g G

<keine>
L

float, double
long double

dezimale Fließkommazahl
vorzeichenbehafteter Wert im e- oder f- bzw. im E- oder F-Format. Nullen am Ende, ein Dezimalpunkt und ein Vorzeichen werden nur ausgegeben, wenn es notwendig ist. Das e-Format wird nur verwendet, wenn das Resultat im f-Format mehr als .Präzision Stellen ergibt oder mehr als vier führende Nullen erfordert.

- + #
Leerzeichen

a3 A3

<keine>
L

float, double
long double

hexadezimale Fließkommazahl
sonst wie Typ g bzw. G, anstelle des Buchstabens e bzw. E für den Exponenten wird das p bzw. P verwendet, da das e/E zu den hexadezimalen Ziffern gehört.

- + #
Leerzeichen

c

<keine>
l2

int
wint_t 

Zeichen

-

s

<keine>
l3

char *
wchar_t * 

Zeichenkette (Array von char) bzw. Zeichenkette (Array von Multibytes) bis zu einem Nullzeichen oder dem Erreichen der durch .Präzision vorgegebene Zeichenzahl.

-

p1

<keine>
F4
N4

void *

Compilerabhängig; Far (F) und Near (N) -Zeiger sind nur in 16-Bit-Compilern enthalten.

Compiler-
abhängig

%

<keine>

-

Ausgabe des Zeichen %.

<keine>

1 erst seit C89;   2 erst seit C95;   3 erst seit C99
4 gehört nicht zum C-Standard, ist aber in vielen C-Compilern implementiert

Beispiel:

kap05_01.c

01 #include <stdio.h>
02
03 int main()
04 {
05    int Zahl = 125;
06    float Reel = 3033.1415f;
07    char Zeichen = 'a';
08
09    printf("Textausgabe ohne Variablen\n");
10    printf("Die Variable Zahl hat den Wert %i\n", Zahl);
11    printf("Variable Zahl in hex. Darstellung: %X\n", Zahl);
12    printf("Die Variable Reel hat den Wert %f\n", Reel);
13    printf("Variable Reel in Exponentendarstellung: %e\n", Reel);
14    printf("Die Variable Zeichen hat %c als Inhalt.\n", Zeichen);
15
16    return 0;
17 }

Dieses Beispielprogramm erzeugt folgende Bildschirmausgabe:

Textausgabe ohne Variablen
Die Variable Zahl hat den Wert 125
Variable Zahl in hex. Darstellung: 7D
Die Variable Reel hat den Wert 3033.141602
Variable Reel in Exponentendarstellung: 3.033142e+03
Die Variable Zeichen hat a als Inhalt.


Mit der Typangabe alleine können bereits die meisten Bildschirmausgaben bewerkstelligt werden. Für die Feinheiten stehen die optionalen Angaben zur Verfügung:

Flags

Ausgabe

-

linksbündige Ausgabe (im Normalfall werden Zahlen rechtsbündig ausgegeben)

+

numerische Ausgabe immer mit Vorzeichen (im Normalfall wird nur bei negativen Zahlen ein Vorzeichen ausgegeben)

Leerzeichen

Positiven Zahlen wird ein Leerzeichen vorangestellt; wird dieses zusammen mit dem + verwendet, wird das Leerzeichen ignoriert!

#

Alternative Darstellung
Typ o: es wird eine 0 vorangestellt
Typ x/X: es wird "0x" bzw. "0X" vorangestellt
Typ e/E/f: es wird ein Dezimalpunkt ausgegeben, auch wenn es keine Nachkommastellen gibt
Typ g/G: wie bei e und E, zusätzlich werden folgende Nullen nicht unterdrückt

 

 

Breite

Ausgabe

n

(n: Dezimalzahl) Es werden mind. n Zeichen ausgegeben und notfalls Leerzeichen vorangestellt.

0n

(0n: Dezimalzahl mit vorangestellter 0) Es werden mind. n Zeichen ausgegeben und notfalls Nullen vorangestellt.
Anstelle einer Zahl kann auch ein Stern ('*') eingesetzt werden. Es muss dann aber in der Argumentenliste die Breite als int angegeben werden.
Beispiel:
int Breite = 5, Wert = 1;

printf("%5d\n", Wert);
printf("%*d\n", Breite, Wert);

 

 

.Präzision

Ausgabe

.0

Standardvorgabe für ganze Zahlen;
keine Ausgabe von Dezimalpunkt und Nachkommastellen für Fließkommazahlen (Typ e, E, f, F, g, G, a und A)

.n

(n: Dezimalzahl)
Mindestanzahl von auszugebenen Ziffern für ganze Zahlen (Typ d, i, u, o, x und X);
Ausgabe von n signifikanten Nachkommastellen für Fließkommazahlen (Typ e, E, f und F);
Ausgabe von n signifikanten Ziffern für Fließkommazahlen (Typ g, G, a und A);
maximale Anzahl von auszugebenen Zeichen für Zeichenketten (Typ s).
Auch für die Präzision kann anstelle einer Zahl ein Stern ('*') eingesetzt werden. Es muss dann in der Argumentenliste die Präzision als int angegeben werden. Wenn für beide, Breite und Präzision, ein Stern eingesetzt wird, muss in der Argumentenliste erst die Angabe der Breite und dann die der Präzision erfolgen.
Beispiel:
int Breite = 5, Praezision = 3;
float Wert = 1;

printf("%5.3f\n", Wert);
printf("%*.*f\n", Breite, Praezision, Wert);


Beispiel:

Nun wird das obige Beispielprogramm um diese optionalen Angaben erweitert:

kap05_02.c

01 #include <stdio.h>
02
03 int main()
04 {
05    int Zahl = 125;
06    float Reel = 3033.1415f;
07    char Zeichen = 'a';
08
09    printf("Textausgabe ohne Variablen\n");
10    printf("Die Variable Zahl hat den Wert %+05i\n", Zahl);
11    printf("Variable Zahl in hex. Darstellung: %#X\n", Zahl);
12    printf("Die Variable Reel hat den Wert %.10f\n", Reel);
13    printf("Variable Reel in Exponentendarst.: %015.3e\n", Reel);
14    printf("Zeichen hat %-3c als Inhalt.\n", Zeichen);
15
16    return 0;
17 }

Diesmal wird folgende Bildschirmausgabe erzeugt:

Textausgabe ohne Variablen
Die Variable Zahl hat den Wert +0125
Variable Zahl in hex. Darstellung: 0X7D
Die Variable Reel hat den Wert 3033.1416015625
Variable Reel in Exponentendarst.: 0000003.033e+03
Zeichen hat a   als Inhalt.


5.2. Dateneingabe über die Tastatur

Damit die "Kommunikation" zwischen Computer und Benutzer nicht einseitig aus Bildschirmausgaben besteht, ist es notwendig, dass der Benutzer Eingaben machen kann, die dem Programm (genauer: einer oder mehreren Variablen) übergeben werden. Zur Dateneingabe über die Tastatur wird in erster Linie der Befehl scanf verwendet. Die komplette Syntax lautet:
int scanf(const char *format [,argument_1 ... ,argument_n]);

Der Aufbau der Syntax sowie die einzelnen Parameter für den Befehl sind ganz ähnlich mit denen des printf-Befehls. Hier haben die einzelnen Wörter die folgenden Bedeutungen:

int

Der Datentyp vor dem Befehl gibt an, was der Befehl als Ergebnis zurückgibt. In diesem Fall ist es eine ganze Zahl (int), die angibt, wieviele Werte insgesamt fehlerfrei eingelesen wurden. Im Falle eines Fehlers ist das Ergebnis gleich dem Wert EOF.

scanf

der eigentliche Befehl

( ... )

Innerhalb dieser runden Klammern werden dem Befehl die Parameter übergeben.

const char *format

Der erste Parameter ist eine Zeichenkette, d.h. eine Folge von Zeichen, die in Anführungsstrichen stehen. In dieser Zeichenkette stehen die Formatierungen für die einzugebenden Daten. Über die Formatierungsangaben wird auch die Anzahl der einzulesenden Daten festgelegt. Die verschiedenen Formatierungsmöglichkeiten sind in der nächsten Tabelle aufgeführt. Mehr zu Zeichenketten finden Sie im Kapitel Strukturierte Datentypen.

argument

Nach der Formatierungsangabe folgen die Variablennamen, jeweils getrennt mit einem Komma. Die Variablen müssen allerdings als Zeiger angegeben werden, d.h. es muss ein kaufmännisches Und (&) vor jeden Variablennamen gesetzt werden. Mehr zu Zeiger finden Sie im Kapitel Zeiger.


Die Formatierungsanweisung ist ganz ähnlich wie bei dem printf-Befehl und ist wie folgt aufgebaut:
%[*][Breite][F|N][hh|h|l|ll|L]Typ

Auch hier beginnt jede Formatierungsanweisung mit einem Prozentzeichen. Auf dieses Zeichen folgen:

[*]

Eine (optionale) Angabe, mit der die Zuweisung zum korrespondierenden Zeiger unterdrückt wird

[Breite]

Eine (optionale) Angabe über die maximal zu lesende Zeichenzahl. Wird vor dem Erreichen der maximalen Zeichenanzahl ein sogenanntes "weißes" Leerzeichen (Trennzeichen wie Leerzeichen, Tabulator, Eingabetaste, ...) eingegeben, wird die Eingabe dieses Wertes beendet und zum nächsten einzugebenden Wert gesprungen.

[F|N]

Eine (optionale) Angabe der Größe des Adress-Parameters (N = Near-Zeiger, F = Far-Zeiger. Diese Angabe ist nur notwendig, wenn die Größe des Parameters von der Standardgröße abweicht.

[hh|h|l|ll|L]

Eine (optionale) Angabe der Größe des Parameters. Genauere Angaben sind in der nächsten Tabelle enthalten.

Typ

Die Angabe des Typs des einzulesenden Wertes (siehe nächste Tabelle). Diese Angabe muss auf jeden Fall gemacht werden!


Die folgende Tabelle gibt alle möglichen Typen an. Dabei wird erst einmal davon ausgegangen, dass keine optionalen Angaben gemacht werden, d.h. keine Breite usw.

Typ

optionale
Größen-
angabe

Datentyp des Parameters:
Zeiger auf

Eingabe

d

<keine>
hh3
h1
l
ll3

int
char 
short 
long
long long3

dezimaler Integer

i1

<keine>
hh3
h1
l
ll3

int
char 
short 
long
long long3

dezimaler Integer;
oktaler Integer (bei führender 0 und Ziffern 0 ... 7);
hexadezimaler Integer (bei führendem 0x bzw. 0X)

u

<keine>
hh3
h1
l
ll3

unsigned int
unsigned char 
unsigned short 
unsigned long
unsigned long long3

dezimaler Integer (nur positive Zahl)

o

<keine>
hh3
h1
l
ll3

unsigned int
unsigned char 
unsigned short 
unsigned long
unsigned long long3

oktaler Integer (unabhängig von führender 0)

x

<keine>
hh3
h1
l
ll3

unsigned int
unsigned char 
unsigned short 
unsigned long
unsigned long long3

hexadezimaler Integer (unabhängig von führendem 0x bzw. 0X)

c

<keine>
l1

char
wchar_t 

Zeichen (1 Byte)
Zeichen (Multibyte)

s

<keine>
l2

char
wchar_t 

Zeichenkette (Array von char)
Zeichenkette (Array von Multibytes)

p1

<keine>

Zeiger auf void

hexadezimaler Integer, der als Speicheradresse interpretiert wird

f
e
g 
a
4

<keine>
l
L
1

float
double
long double
 

dezimale Fließkommazahl

[

<keine>
l2

char
wchar_t 

Zeichenkette (Array von char)
Zeichenkette (Array von Multibytes)
(siehe Anmerkungen am Ende des Kapitels!)

1 erst seit C89;   2 erst seit C95;   3 erst seit C99
4 gehört nicht zum C-Standard, ist aber in vielen C-Compilern implementiert

Die folgenden Angaben gehören wohl nicht zum Standard-C, werden aber von einigen Compilern akzeptiert.

Typ

entspricht Typ

Datentyp des Parameters:
Zeiger auf

Eingabe

D

ld

long

dezimaler Integer

I

li

long

dezimaler Integer

U

lu

unsigned long

dezimaler Integer

O

lo

unsigned long

oktaler Integer

X

lx

unsigned long

hexadezimaler Integer

E

e

float

dezimale Fließkommazahl

G

lg

double

dezimale Fließkommazahl


Beispiel:

kap05_03.c

01 #include <stdio.h>
02
03 int main()
04 {
05    int i;
06    float f;
07
08    printf("Bitte eine ganze Zahl & eine reele Zahl eingeben: ");
09    scanf("%i %f", &i, &f);
10    printf("Sie haben %i und %f eingegeben!\n", i, f);
11
12    return 0;
13 }

Im Formatstring von scanf dürfen nur Platzhalter und Leerzeichen verwendet werden!

Nun noch einige Besonderheiten beim Einlesen von Strings:

Bei der Eingabe von Strings kann anstelle des Formats %s auch das Format %[Suchzeichen] verwendet werden. Suchzeichen ist eine Folge von Zeichen, aus denen die Eingabe bestehen muss.
Beispiel: %[abcd] erwartet nur Eingaben, die aus den Zeichen a, b, c und d bestehen, bei jedem anderen Zeichen ist die Eingabe beendet.

Wird als erstes Suchzeichen das Carret (^) verwendet, wird die Eingabe beendet, wenn eines der Suchzeichen eingegeben wird.
Beispiel: %[^abcd] erwartet nur Eingaben, die nicht aus den Zeichen a, b, c und d bestehen. Die Eingabe wird in diesem Fall auch nicht von den sogenannten "weissen Leerzeichen" beendet, sondern nur durch die angegebenen Suchzeichen oder durch das Erreichen der mit Breite festgelegten Zeichenzahl.

Anstelle von Zeichenaufzählungen können auch Bereiche angegeben werden.
Beispiel: %[0123456789] ist äquivalent mit %[0-9].

Bei manchen Compilern kann bzw. muss bei der Formatangabe das s angehangen werden (also %[Suchzeichen]s anstelle von %[Suchzeichen] ).



Voriges Kapitel: 4. Datentypen in C