Ausgabe und Eingabe¶
Das Ausgeben und Einlesen von Daten über den Bildschirm erfolgt häufig mittels
der Funktionen printf()
und scanf()
.[1] Beide Funktionen sind Teil der
Standard-Bibliothek stdio.h, so
dass diese zu Beginn der Quellcode-Datei mittels include <stdio.h>
eingebunden werden muss.[2]
printf()
– Daten formatiert ausgeben¶
Die Funktion printf()
dient grundsätzlich zur direkten Ausgabe von
Zeichenketten auf dem Bildschirm; beispielsweise gibt printf("Hallo Welt!")
die angegebene Zeichenkette auf dem Bildschirm aus. Innerhalb der Zeichenketten
können allerdings Sonderzeichen sowie Platzhalter für beliebige Variablen und
Werte eingefügt werden.
Zeichen | Bedeutung |
\n |
Neue Zeile |
\t |
Tabulator (4 Leerzeichen) |
\\ |
Backslash-Zeichen \ |
\' |
Einfaches Anführungszeichen |
\" |
Doppeltes Anführungszeichen |
Die in der obigen Tabelle angegebenen Sonderzeichen werden auch „Escape-Sequenzen“ genannt, da sie nur mittels des vorangehenden Backslash-Zeichens, das ihre sonstige Bedeutung aufhebt, innerhalb einer Zeichenkette dargestellt werden können.
Ein Platzhalter besteht aus einem %
-Zeichen, gefolgt von einem oder mehreren
Zeichen, welche den Typ der auszugebenden Werte oder Variablen angeben und
gleichzeitig festlegen, wie die Ausgabe formatiert werden soll. Damit kann
beispielsweise bestimmt werden, wie viele Stellen für einen Wert reserviert
werden sollen, ob die Ausgabe links- oder rechtsbündig erfolgen soll, und/oder
ob bei der Ausgabe von Zahlen gegebenenfalls führende Nullen angefügt werden
sollen.
// Den Wert Pi auf sechs Nachkommastellen genau ausgeben:
printf("Der Wert von Pi ist %.6f...\n", 3.141592653589793)
// Ergebnis: Der Wert von Pi ist 3.141593...
// Maximal dreistellige Zahlen rechtsbündig ausgeben:
printf("%3i:\n%3i:\n%3i:\n", 1, 10, 100);
// Ergebnis:
// 1:
// 10:
// 100:
// Maximal dreistellige Zahlen linksbündig ausgeben:
printf("%3i:\n%3i:\n%3i:\n", 1, 10, 100);
// Ergebnis:
// 1 :
// 10 :
// 100:
// Einstelligen Zahlen eine Null voranstellen:
printf("%02i.:\n%02i.:\n%02i.:\n", 8, 9, 10);
// Ergebnis:
// 08.:
// 09.:
// 10.:
In den obigen Beispielen wurden der Funktion printf()
zwei oder mehr
Argumente übergeben. Beim ersten Argument handelt es sich um einen so genannten
Formatstring, bei den folgenden Argumenten um die auf dem Bildschirm
auszugebenden Werte. Falls diese, wie im ersten Beispiel, mehr Nachkommastellen
haben als in der Formatierung vorgesehen (Die Angabe %.6f
steht für einen
Wert vom Datentyp float
sechs Nachkommastellen), so wird der Wert
automatisch auf die angegebene Genauigkeit gerundet.
Zur Festlegung des Datentyps einer auszugebenden Variablen gibt es allgemein folgende Umwandlungszeichen:
Zeichen | Argument | Bedeutung |
d, i |
int |
Dezimal-Zahl mit Vorzeichen. |
o |
int |
Oktal-Zahl ohne Vorzeichen (und ohne führende Null). |
x, X |
int |
Hexadezimal-Zahl ohne Vorzeichen (und ohne führendes 0x oder
0X ), also abcdef bei 0x oder ABCDEF bei 0X . |
u |
int |
Dezimal-Zahl ohne Vorzeichen. |
c |
int |
Ein einzelnes Zeichen (unsigned char ). |
s |
char * |
Zeichen einer Zeichenkette bis zum Zeichen \0 , oder bis zur
angegebenen Genauigkeit. |
f |
double |
Dezimal-Zahl als [-]mmm.ddd , wobei die angegebene Genauigkeit die
Anzahl der d festlegt. Die Voreinstellung ist 6 , bei 0
entfällt der Dezimalpunkt. |
e, E |
double |
Dezimal-Zahl als [-]m.dddddde±xx oder [-]m.ddddddE±xx , wobei die
angegebene Genauigkeit die Anzahl der d festlegt. Die Voreinstellung
ist 6 , bei 0 entfällt der Dezimalpunkt. |
g, G |
double |
Dezimal-Zahl wie wie %e oder %E . Wird verwendet, wenn der
Exponent kleiner als die angegebene Genauigkeit ist; unnötige Nullen am
Schluss werden nicht ausgegeben. |
p |
void * |
Zeiger (Darstellung hängt von Implementierung ab). |
n |
int * |
Anzahl der aktuell von printf() ausgegebenen Zeichen. |
Die obigen Formatangaben lassen sich durch Steuerzeichen („flags“) zwischen dem
%
- und dem Umwandlungszeichen weiter modifizieren:
Zahl
: Minimale Feldbreite festlegen: Das umgewandelte Argument wird in einem Feld ausgegeben, das mindestens so breit ist, bei Bedarf aber auch breiter. Hat das umgewandelte Argument weniger Zeichen als die Feldbreite es verlangt, so werden auf der linken Seite Leerzeichen eingefügt..Zahl
: Genauigkeit von Gleitkommazahlen festlegen: Gibt die maximale Anzahl von Zeichen an, die nach dem Dezimalpunkt ausgegeben werden-
: Ausrichten des umgewandelten Arguments am linken Rand des Ausgabefeldes (Leerzeichen werden bei Bedarf nicht links, sondern rechts eingefügt)+
: Ausgabe einer Zahl stets mit VorzeichenLeerzeichen
: Ausgabe eines Leerzeichens vor einer Zahl, falls das erste Zeichen kein Vorzeichen ist0
: Zahlen bei der Umwandlungen bis zur Feldbreite mit führenden Nullen aufüllen
Anstelle einer Zahl kann auch das Zeichen *
als Feldbreite angegeben werden.
In diesem Fall wird die Feldbreite durch eine zusätzlich an dieser Stelle in der
Argumentliste angegebenen int
-Variablen festgelegt:
int zahl = 1000;
int breite = 5;
printf("Der Wert von der Variable \"zahl\" ist: %*d", breite, zahl);
Die Formatangaben %e
und %g
können gleichermaßen zur Ausgabe von
Gleitkomma-Zahlen in der Zehnerpotenz-Schreibweise verwendet werden. Sie
unterscheiden sich nur bei Zahlen mit wenig Nachkommastellen. Beispielsweise
würde die Ausgabe printf("%g\n", 2.15);
als Ergebnis 2.15
anzeigen,
während printf("%e\n", 2.15);
als Ergebnis 2.150000e+00
liefern würde.
Soll eine long
-Variante eines Integers ausgegeben werden, so muss vor das
jeweilige Umwandlungszeichen ein l
geschrieben werden, beispielsweise lu
für long unsigned int
oder ld
für long int
; für long double
wird L
geschrieben.
Soll das %
-Zeichen innerhalb einer Zeichenkette selbst ausgegeben werden, so
muss an dieser Stelle %%
geschrieben werden.
Soll über mehrere Zeilen hinweg Text mittels printf()
ausgegeben werden, so
ist meist es für eine bessere Lesbarkeit empfehlenswert, für jede neue Zeile
eine eigene printf()
-Anweisung zu schreiben.
puts()
– Einzelne Zeichenketten ausgeben¶
Sollen nur einfache Zeichenketten (ohne Formatierung und ohne Variablenwerte)
ausgegeben werden, so kann anstelle von printf()
auch die Funktion
puts()
aus der Standard-Bibliothek stdio.h verwendet
werden. Die in der Tabelle Escape-Sequenzen
aufgelisteten Sonderzeichen können auch bei puts()
verwendet werden, es muss
jedoch am Ende einer Ausgabezeile kein \n
angehängt werden; puts()
gibt
automatisch jeden String in einer neuen Zeile aus.
putchar()
– Einzelne Zeichen ausgeben¶
Mittels putchar()
können einzelne Zeichen auf dem Bildschirm ausgegeben
werden. Diese Funktion wird nicht nur von den anderen Ausgabefunktionen
aufgerufen, sondern kann auch verwendet werden, wenn beispielsweise eine Datei
zeichenweise eingelesen und nach Anwendung eines Filters wieder zeichenweise auf
dem Bildschirm ausgegeben werden soll.[3]
scanf()
– Daten formatiert einlesen¶
Die Funktion scanf()
kann als flexible Funktion verwendet werden, um Daten
direkt vom Bildschirm beziehungsweise von der Tastatur einzulesen. Dabei wird
bei scanf()
, ebenso wie bei printf()
, ein Formatstring angegeben, der
das Format der Eingabe festlegt. Die Funktion weist dann die eingelesen Daten,
die dem Format entsprechen, vom Bildschirm ein und weist ihnen eine oder mehrere
Programmvariablen zu. Im Formatstring können die gleichen
Umwandlungszeichen wie bei printf()
verwendet werden.
Die Eingabe mittels scanf()
erfolgt „gepuffert“, d.h. die mit der Tastatur
eingegebenen Zeichen werden zunächst in einem Zwischenspeicher („Puffer“) des
Betriebsystems abgelegt. Erst, wenn der Benutzer die Enter
-Taste drückt,
wird der eingegebene Text von scanf()
verarbeitet.
Bei der Zuweisung der eingelesenen Daten wird bei Benutzung der Funktion
scanf()
nicht der jeweilige Variablenname, sondern stets die zugehörige
Speicheradresse angegeben, an welcher die Daten abgelegt werden sollen; diese
kann leicht mittels des Adress-Operators &
bestimmt
werden. Um also beispielsweise einen int
-Wert vom Bildschirm einzulesen,
gibt man folgendes ein:
int n;
// Benutzer zur Eingabe auffordern:
printf("Bitte einen ganzzahligen Wert eingeben: ")
// Eingegebenen Wert einlesen:
scanf("%i", &n);
Sobald der Benutzer seine Eingabe mit Enter
bestätigt, wird im obigen
Beispiel die eingegebene Zahl eingelesen und am Speicherplatz der Variablen
n
hinterlegt.
Zum Einlesen von Zeichenketten muss dem Variablennamen kein &
vorangestellt
werden, da es sich bei einer Zeichenkette um ein Array handelt.
Dieses wiederum entspricht einem Zeiger auf den ersten Eintrag,
und ab eben dieser Stelle soll die eingelesene Zeichenkette abgelegt werden.
Beim Einlesen von Daten in Felder muss allerdings beachtet werden, dass der
angegebene Zeiger bereits initialisiert wurde.
Eine simple Methode, um dies sicherzustellen, ist dass eine String-Variable
nicht mit char *mystring;
, sondern beispielsweise mit char
mystring[100];
definiert wird.
Whitespace als Trennzeichen
Mit einer einzelnen scanf()
-Funktion können auch mehrere Werte gleichzeitig
eingelesen werden, wenn mehrere Umwandlungszeichen im Formatstring und
entsprechend viele Speicheradressen als weitere Argumente angegeben werden. Beim
Einlesen achtet scanf()
dabei so genannte Whitespace-Zeichen (Leerzeichen,
Tabulator-Zeichen oder Neues-Zeile-Zeichen), um die einzelnen Daten voneinander
zu trennen. Soll der Benutzer beispielsweise zwei beliebige Zahlen eingeben, so
können diese mit einem einfachen Leerzeichen zwischen ihnen, aber ebenso in
zwei getrennten Zeilen eingegeben werden.
int n1, n2;
// Benutzer zur Eingabe auffordern:
printf("Bitte zwei beliebige Werte eingeben: ")
// Eingegebene Werte einlesen:
scanf("%f %f", &n1, &n2);
fflush()
– Zwischenspeicher löschen
Da die Daten bei Verwendung von scanf()
zunächst in einen Zwischenspeicher
eingelesen werden, können Probleme auftreten, wenn der Benutzer mehr durch
Whitespace-Zeichen getrennte Werte eingibt, als beim Aufruf der Funktion
scanf()
verarbeitet werden. Die restlichen Werte verbleiben in diesem Fall
im Zwischenspeicher und würden beim nächsten Aufruf von scanf()
noch vor der
eigentlich erwarteten Eingabe verarbeitet werden. Eine Abhilfe hierfür schafft
die Funktion fflush()
, die nach jedem Aufruf von scanf()
aufgerufen
werden sollte und ein Löschen aller noch im Zwischenspeicher abgelegten Werte
bewirkt.
Beim Einlesen von Zeichenketten mittels %s
ist das wortweise Einlesen von
scanf()
oftmals hinderlich, da in der mit %s
verknüpften Variable nur
Text bis zum ersten Whitespace-Zeichen (Leerzeichen, Tabulator-Zeichen oder
Neues-Zeile-Zeichen) gespeichert wird. Ganze Zeilen, die aus beliebig vielen
Wörtern bestehen, sollten daher bevorzugt mittels gets()
oder fgets()
eingelesen werden.
gets()
und fgets()
– Einzelne Zeichenketten einlesen¶
Um eine Textzeile auf einmal einzulesen, kann die Funktion gets()
aus der
Standard-Bibliothek stdio.h verwendet werden. Diese Funktion
liest eine Textzeile vom Bildschirm ein und speichert sie in der angegebenen
Variablen ein:
int mystring[81];
gets(mystring);
Ein Neues-Zeile-Zeichen \n
am Ende des Eingabestrings wird von gets()
automatisch abgeschnitten, das Zeichen \0
zum Beenden der Zeichenkette
automatisch angefügt. Wichtig ist allerdings bei der Verwendung von gets()
,
dass der angegebene String-Pointer auf ein ausreichend großes Feld zeigt. Im
obigen Beispiel darf die eingelesene Zeile somit nicht mehr als
Zeichen haben, da auch noch Platz für das Zeichen \0
bleiben muss. Werden
die Feldgrenzen überschritten, kann dies ein unkontrolliertes Verhalten des
Programms oder gar einen Programmabsturz zur Folge haben.[4]
Als bessere Alternative zu gets()
kann die Funktion fgets()
verwendet
werden, welche die Anzahl der maximal eingelesenen Zeichen beschränkt:
int mystring[81];
int n = 80;
fgets(mystring, n, stdin);
Im Unterschied zu gets()
speichert fgets()
das Neue-Zeile-Zeichen \n
mit in der eingelesenen Zeichenkette, was unter Umständen bei der Längenangabe
berücksichtigt werden muss. Die Funktion fgets()
gibt, wenn eine
Zeichenkette erfolgreich eingelesen wurde, einen Zeiger als Ergebnis zurück, der
mit der Speicheradresse der angegebenen Stringvariablen übereinstimmt; bei einem
Fehler wird NULL
als Ergebnis zurück gegeben.
Um eine Textzeile auf einmal einzulesen, kann die Funktion gets()
aus der
Standard-Bibliothek stdio.h verwendet werden. Diese Funktion
liest eine Textzeile vom Bildschirm ein und speichert sie in der angegebenen
Variablen ein:
getchar()
– Einzelne Zeichen einlesen¶
Um einzelne Zeichen vom Standard-Eingang (Bildschirm bzw. Tastatur) zu lesen,
kann die Funktion getchar()
verwendet werden.[5] Ebenso wie bei der Funktion
scanf()
gibt die Funktion erst dann das gelesene Zeichen als Ergebnis
zurück, wenn der Benutzer die Enter
-Taste drückt; dies lässt sich
beispielsweise für eine Abfrage der Art [Yn]
für "Yes"
oder "No"
nutzen, wobei üblicherweise der groß geschriebene Buchstabe als Vorauswahl gilt
und gesetzt wird, wenn keine explizite Eingabe vom Benutzer erfolgt.
Wird das Zeichen nach einer Umlenkung des Standard-Eingangs (beispielsweise
mittels freopen()) nicht von der Tastatur, sondern von einer
Datei eingelesen, so wird so lange jeweils ein einzelnes Zeichen
zurückgegeben, bis ein Fehler auftritt oder die Funktion auf das Ende des
Datenstroms bzw. der Datei trifft; in diesem Fall wird EOF
als Ergebnis
zurückgegeben.
… to be continued …
Anmerkungen:
[1] | Um Daten von Dateien anstelle vom Bildschirm einzulesen, gibt es weitere Funktionen, die im Abschnitt Dateien und Verzeichnisse näher beschrieben sind. |
[2] | Genau genommen erfolgt bei der Funktion Ebenso liest die Funktion |
[3] | Streng genommen handelt es sich bei putchar() nicht um eine Funktion,
sondern um ein Makro: Letztlich wird putchar(Zeichen) vom
Präprozessor durch einen Funktionsaufruf von fputc(Zeichen, stdin)
ersetzt. Die Funktion fputc() wird im Abschnitt Dateien und
Verzeichnisse näher beschrieben. |
[4] | Im neuen C11-Standard wird gets() aufgrund seiner Fehleranfälligkeit
nicht mehr als Standard gelistet, den ein Compiler abdecken muss. Da die
Funktion in sehr vielen Programmcodes vorkommt, wird gcc wohl auch in
absehbarer Zukunft diese Funktion unterstützen. In C11 wurde dafür die
ähnliche Funktion gets_s() im optionalen Teil von stdio.h
aufgenommen, die jedoch ebenfalls nicht jeder Compiler zwingend unterstützen
muss. Dies ist ein weiterer Grund, bevorzugt fgets() zu verwenden. |
[5] | Streng genommen handelt es sich bei getchar() nicht um eine Funktion,
sondern um ein Makro. Letztlich wird getchar() vom
Präprozessor durch einen Funktionsaufruf von fgetc(stdin) ersetzt.
Die Funktion fputc() wird im Abschnitt Dateien und Verzeichnisse näher beschrieben. |