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 |
Datentyp des |
Ausgabe |
erlaubte |
d i1 |
<keine> |
int |
dezimaler Integer |
- + |
u |
<keine> |
unsigned int |
dezimaler Integer |
- + |
o |
<keine> |
unsigned int |
oktaler Integer |
- + # |
x X |
<keine> |
unsigned int |
hexadezimaler Integer |
- + # |
f F4 |
<keine> |
float, double |
dezimale Fließkommazahl |
- + # |
e E |
<keine> |
float, double |
dezimale Fließkommazahl |
- + # |
g G |
<keine> |
float, double |
dezimale Fließkommazahl |
- + # |
a3 A3 |
<keine> |
float, double |
hexadezimale Fließkommazahl |
- + # |
c |
<keine> |
int |
Zeichen |
- |
s |
<keine> |
char * |
Zeichenkette (Array von char) bzw. Zeichenkette (Array von Multibytes) bis zu einem Nullzeichen oder dem Erreichen der durch .Präzision vorgegebene Zeichenzahl. |
- |
p1 |
<keine> |
void * |
Compilerabhängig; Far (F) und Near (N) -Zeiger sind nur in 16-Bit-Compilern enthalten. |
Compiler- |
% |
<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 |
|
|
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. |
|
|
.Präzision |
Ausgabe |
.0 |
Standardvorgabe für ganze Zahlen; |
.n |
(n: Dezimalzahl) |
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 |
Datentyp des Parameters: |
Eingabe |
d |
<keine> |
int |
dezimaler Integer |
i1 |
<keine> |
int |
dezimaler Integer; |
u |
<keine> |
unsigned int |
dezimaler Integer (nur positive Zahl) |
o |
<keine> |
unsigned int |
oktaler Integer (unabhängig von führender 0) |
x |
<keine> |
unsigned int |
hexadezimaler Integer (unabhängig von führendem 0x bzw. 0X) |
c |
<keine> |
char |
Zeichen (1 Byte) |
s |
<keine> |
char |
Zeichenkette (Array von char) |
p1 |
<keine> |
Zeiger auf void |
hexadezimaler Integer, der als Speicheradresse interpretiert wird |
f |
<keine> |
float |
dezimale Fließkommazahl |
[ |
<keine> |
char |
Zeichenkette (Array von char) |
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: |
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
Nächstes Kapitel: 6. Kontrollstrukturen