C-Programmierung: Einfache Ein- und Ausgabe
Wohl kein Programm kommt ohne Ein- und Ausgabe aus. In C ist die Ein-/Ausgabe allerdings kein Bestandteil der Sprache selbst. Vielmehr liegen Ein- und Ausgabe als eigenständige Funktionen vor, die dann durch den Linker eingebunden werden. Die wichtigsten Ein- und Ausgabefunktionen werden Sie in diesem Kapitel kennenlernen.
printf
[Bearbeiten]Die Funktion printf
haben wir bereits in unseren bisherigen Programmen benutzt. Zeit also, sie genauer unter die Lupe zu nehmen. Die Funktion printf
hat die folgende Syntax:
int printf (const char *format, ...);
Bevor wir aber printf
diskutieren, sehen wir uns noch einige Grundbegriffe von Funktionen an. In einem späteren Kapitel werden Sie dann lernen, wie Sie eine Funktion selbst schreiben können.
In den beiden runden Klammern befinden sich die Parameter. In unserem Beispiel ist der Parameter const char *format
. Die drei Punkte dahinter zeigen an, dass die Funktion noch weitere Parameter erhalten kann. Die Werte, die der Funktion übergeben werden, bezeichnet man als Argumente. In unserem „Hallo Welt“-Programm haben wir der Funktion printf
beispielsweise das Argument "Hallo Welt" übergeben.
Außerdem kann eine Funktion einen Rückgabewert besitzen. In diesem Fall ist der Typ des Rückgabewertes int
. Den Typ der Rückgabe erkennt man am Schlüsselwort, das vor der Funktion steht. Eine Funktion, die keinen Wert zurückgibt, erkennen Sie an dem Schlüsselwort void
.
Die Bibliotheksfunktion printf
dient dazu, eine Zeichenkette (engl. String) auf der Standardausgabe auszugeben. In der Regel ist die Standardausgabe der Bildschirm. Als Übergabeparameter besitzt die Funktion einen Zeiger auf einen konstanten String. Was es mit Zeigern auf sich hat, werden wir später noch sehen. Das const
bedeutet hier, dass die Funktion den String nicht verändert. Über den Rückgabewert liefert printf
die Anzahl der ausgegebenen Zeichen. Wenn bei der Ausgabe ein Fehler aufgetreten ist, wird ein negativer Wert zurückgegeben.
Als erstes Argument von printf
sind nur Strings erlaubt. Bei folgender Zeile gibt der Compiler beim Übersetzen deshalb eine Warnung oder einen Fehler aus:
printf(55); // falsch
Da die Anführungszeichen fehlen, nimmt der Compiler an, dass es sich bei 55 um einen Zahlenwert handelt. Geben Sie dagegen 55 in Anführungszeichen an, interpretiert der Compiler dies als Text. Bei der folgenden Zeile gibt der Compiler deshalb keinen Fehler aus:
printf("55"); // richtig
Formatelemente von printf
[Bearbeiten]Die printf
-Funktion kann auch mehrere Parameter verarbeiten, diese müssen dann durch Kommata voneinander getrennt werden.
Beispiel:
#include <stdio.h>
int main()
{
printf("%i plus %i ist gleich %s.\n", 3, 2, "Fünf");
return 0;
}
Ausgabe:
3 plus 2 ist gleich Fünf.
Die mit dem %-Zeichen eingeleiteten Formatelemente greifen nacheinander auf die durch Komma getrennten Parameter zu (das erste %i
auf 3, das zweite %i
auf 2 und %s
auf den String "Fünf").
Innerhalb von format
werden Umwandlungszeichen (engl. conversion modifier) für die weiteren Parameter eingesetzt. Hierbei muss der richtige Typ verwendet werden.
Die wichtigsten Umwandlungszeichen sind:
Zeichen | Umwandlung |
---|---|
%d oder %i | int |
%c | einzelnes Zeichen |
%e oder %E | double im Format [-]d.ddd e±dd bzw. [-]d.ddd E±dd |
%f | double im Format [-]ddd.ddd |
%o | int als Oktalzahl ausgeben |
%p | die Adresse eines Zeigers |
%s | Zeichenkette ausgeben |
%u | unsigned int |
%lu | long unsigned |
%x oder %X | int als Hexadezimalzahl ausgeben |
%% | Prozentzeichen |
Weitere Formate und genauere Erläuterungen finden Sie in der Referenz dieses Buches.
Beispiel:
#include <stdio.h>
int main()
{
printf("Integer: %d\n", 42);
printf("Double: %.6f\n", 3.141);
printf("Zeichen: %c\n", 'z');
printf("Zeichenkette: %s\n", "abc");
printf("43 Dezimal ist in Oktal: %o\n", 43);
printf("43 Dezimal ist in Hexadezimal: %x\n", 43);
printf("Und zum Schluss geben wir noch das Prozentzeichen aus: %%\n");
return 0;
}
Nachdem Sie das Programm übersetzt und ausgeführt haben, erhalten Sie die folgende Ausgabe:
Integer: 42 Double: 3.141000 Zeichen: z Zeichenkette: abc 43 Dezimal ist in Oktal: 53 43 Dezimal ist in Hexadezimal: 2b Und zum Schluss geben wir noch das Prozentzeichen aus: %
Neben dem Umwandlungszeichen kann eine Umwandlungsangabe weitere Elemente zur Formatierung erhalten. Dies sind maximal:
- ein Flag
- die Feldbreite
- durch einen Punkt getrennt die Anzahl der Nachkommstellen (Längenangabe)
- und an letzter Stelle schließlich das Umwandlungszeichen selbst
Flags
[Bearbeiten]Unmittelbar nach dem Prozentzeichen werden die Flags (dt. Kennzeichnung) angegeben. Sie haben die folgende Bedeutung:
-
(Minus): Der Text wird links ausgerichtet.+
(Plus): Es wird auch bei einem positiven Wert ein Vorzeichen ausgegeben.- Leerzeichen: Ein Leerzeichen wird ausgegeben, wenn der Wert positiv ist.
#
: Welche Wirkung das Kennzeichen#
hat, ist abhängig vom verwendeten Format: Wenn ein Wert über%x
als Hexadezimal ausgegeben wird, so wird jedem Wert ein 0x vorangestellt (außer der Wert ist 0).0
: Die Auffüllung erfolgt mit Nullen anstelle von Leerzeichen, wenn die Feldbreite verändert wird.
Im folgenden ein Beispiel, das die Anwendung der Flags zeigt:
#include <stdio.h>
int main()
{
printf("Zahl 67:%+i\n", 67);
printf("Zahl 67:% i\n", 67);
printf("Zahl 67:%#x\n", 67);
printf("Zahl 0:%0x\n", 0);
return 0;
}
Wenn das Programm übersetzt und ausgeführt wird, erhalten wir die folgende Ausgabe:
Zahl 67:+67 Zahl 67: 67 Zahl 67:0x43 Zahl 0:0
Feldbreite
[Bearbeiten]Hinter dem Flag kann die Feldbreite (engl. field width) festgelegt werden. Das bedeutet, dass die Ausgabe mit der entsprechenden Anzahl von Zeichen aufgefüllt wird. Beispiel:
int main()
{
printf("Zahlen rechtsbündig ausgeben: %5d, %5d, %5d\n",34, 343, 3343);
printf("Zahlen rechtsbündig ausgeben, links mit 0 aufgefüllt: %05d, %05d, %05d\n",34, 343, 3343);
printf("Zahlen linksbündig ausgeben: %-5d, %-5d, %-5d\n",34, 343, 3343);
return 0;
}
Wenn das Programm übersetzt und ausgeführt wird, erhalten wir die folgende Ausgabe:
Zahlen rechtsbündig ausgeben: 34, 343, 3343 Zahlen rechtsbündig ausgeben, links mit 0 aufgefüllt: 00034, 00343, 03343 Zahlen linksbündig ausgeben: 34 , 343 , 3343
In Zeile 4 haben wir anstelle der Leerzeichen eine 0 verwendet, so dass nun die Feldbreite mit Nullen aufgefüllt wird.
Standardmäßig erfolgt die Ausgabe rechtsbündig. Durch Voranstellen des Minuszeichens kann die Ausgabe aber auch linksbündig erfolgen, wie in Zeile 5 zu sehen ist.
Nachkommastellen
[Bearbeiten]Nach der Feldbreite folgt, durch einen Punkt getrennt, die Genauigkeit. Bei %f
werden ansonsten standardmäßig 6 Nachkommastellen ausgegeben. Diese Angaben sind natürlich auch nur bei den Gleitkommatypen float
und double
sinnvoll, weil alle anderen Typen keine Nachkommastellen besitzen.
Beispiel:
#include <stdio.h>
int main()
{
double betrag1 = 0.5634323;
double betrag2 = 0.2432422;
printf("Summe: %.3f\n", betrag1 + betrag2);
return 0;
}
Wenn das Programm übersetzt und ausgeführt wurde, erscheint die folgende Ausgabe auf dem Bildschirm:
Summe: 0.807
scanf
[Bearbeiten]Auch die Funktion scanf
haben Sie bereits kennengelernt. Sie hat eine vergleichbare Syntax wie printf
:
int scanf (const char *format, ...);
Die Funktion scanf
liest einen Wert ein und speichert diesen in den angegebenen Variablen ab. Doch Vorsicht: Die Funktion scanf
erwartet die Adresse der Variablen. Deshalb führt der folgende Funktionsaufruf zu einem Fehler:
scanf("%i", x); /* Fehler */
Richtig dagegen ist:
scanf("%i",&x);
Mit dem Adressoperator & erhält man die Adresse einer Variablen. Diese kann man sich auch ausgeben lassen:
#include <stdio.h>
int main(void)
{
int x = 5;
printf("Adresse von x: %p\n", &x);
printf("Inhalt der Speicherzelle: %d\n", x);
return 0;
}
Kompiliert man das Programm und führt es aus, erhält man z.B. die folgende Ausgabe:
Adresse von x: 0022FF74 Inhalt der Speicherzelle: 5
Die Ausgabe der Adresse kann bei Ihnen variieren. Es ist sogar möglich, dass sich diese Angabe bei jedem Neustart des Programms ändert. Dies hängt davon ab, wo das Programm (vom Betriebssystem) in den Speicher geladen wird.
Mit Adressen werden wir uns im Kapitel Zeiger noch einmal näher beschäftigen.
Für scanf
können die folgenden Platzhalter verwendet werden, die dafür sorgen, dass der eingegebene Wert in das "richtige" Format umgewandelt wird:
Zeichen | Umwandlung |
---|---|
%d | vorzeichenbehafteter Integer als Dezimalwert |
%i | vorzeichenbehafteter Integer als Dezimal-, Hexadezimal oder Oktalwert |
%e, %f, %g | Fließkommazahl |
%o | int als Oktalzahl einlesen |
%s | Zeichenkette einlesen |
%x | Hexadezimalwert |
%% | erkennt das Prozentzeichen |
getchar und putchar
[Bearbeiten]Die Funktion getchar
liefert das nächste Zeichen vom Standard-Eingabestrom. Ein Strom (engl. stream) ist eine geordnete Folge von Zeichen, die als Ziel oder Quelle ein Gerät hat. Im Falle von getchar
ist dieses Gerät die Standardeingabe -- in der Regel also die Tastatur. Der Strom kann aber auch andere Quellen oder Ziele haben: Wenn wir uns später noch mit dem Speichern und Laden von Dateien beschäftigen, dann ist das Ziel und die Quelle des Stroms eine Datei.
Das folgende Beispiel liest ein Zeichen von der Standardeingabe und gibt es aus. Eventuell müssen Sie nach der Eingabe des Zeichens <Enter> drücken, damit überhaupt etwas passiert. Das liegt daran, dass die Standardeingabe üblicherweise zeilenweise und nicht zeichenweise eingelesen wird.
int c;
c = getchar();
putchar(c);
Geben wir über die Tastatur "hallo" ein, so erhalten wir durch den Aufruf von getchar
zunächst das erste Zeichen (also das "h"). Durch einen erneuten Aufruf von getchar
erhalten wir das nächste Zeichen, usw. Die Funktion putchar(c)
ist quasi die Umkehrung von getchar
: Sie gibt ein einzelnes Zeichen c auf der Standardausgabe aus. In der Regel ist die Standardausgabe der Monitor.
Zugegeben, die Benutzung von getchar
hat hier wenig Sinn, außer man hat vor, nur das erste Zeichen einer Eingabe einzulesen. Häufig wird getchar
mit Schleifen benutzt. Ein Beispiel dafür werden wir noch später kennenlernen.
Escape-Sequenzen
[Bearbeiten]Eine spezielle Darstellung kommt in C den Steuerzeichen zugute. Steuerzeichen sind Zeichen, die nicht direkt auf dem Bildschirm sichtbar werden, sondern eine bestimmte Aufgabe erfüllen, wie etwa das Beginnen einer neuen Zeile, das Darstellen des Tabulatorzeichens oder das Ausgeben eines Warnsignals. So führt beispielsweise
printf("Dies ist ein Text ");
printf("ohne Zeilenumbruch");
nicht etwa zu dem Ergebnis, dass nach dem Wort „Text“ eine neue Zeile begonnen wird, sondern das Programm gibt nach der Kompilierung aus:
Dies ist ein Text ohne Zeilenumbruch
Eine neue Zeile wird also nur begonnen, wenn an der entsprechenden Stelle ein \n
steht.
Die folgende Auflistung zeigt alle in C vorhandenen Escape-Sequenzen:
\n
(new line) = bewegt den Cursor auf die Anfangsposition der nächsten Zeile.\t
(horizontal tab) = Setzt den Tabulator auf die nächste horizontale Tabulatorposition. Wenn der Cursor bereits die letzte Tabulatorposition erreicht hat, dann ist das Verhalten unspezifiziert (vorausgesetzt eine letzte Tabulatorposition existiert).\a
(alert) = gibt einen hör- oder sichtbaren Alarm aus, ohne die Position des Cursors zu ändern\b
(backspace) = Setzt den Cursor ein Zeichen zurück. Wenn sich der Cursor bereits am Zeilenanfang befindet, dann ist das Verhalten unspezifiziert.\r
(carriage return, dt. Wagenrücklauf) = Setzt den Cursor an den Zeilenanfang\f
(form feed) = Setzt den Cursor auf die Startposition der nächsten Seite.\v
(vertical tab) = Setzt den Cursor auf die nächste vertikale Tabulatorposition. Wenn der Cursor bereits die letzte Tabulatorposition erreicht hat, dann ist das Verhalten unspezifiziert (wenn eine solche existiert).\"
" wird ausgegeben\'
' wird ausgegeben\?
? wird ausgegeben\\
\ wird ausgegeben\0
ist die Endmarkierung einer Zeichenkette
Jede Escape-Sequenz symbolisiert ein Zeichen auf einer Implementierung und kann in einer Variablen des Typs char
gespeichert werden.
Beispiel:
#include <stdio.h>
int main(void)
{
printf("Der Zeilenumbruch erfolgt\n");
printf("durch die Escape-Sequenz \\n\n\n");
printf("Im Folgenden wird ein Wagenrücklauf (carriage return) mit \\r erzeugt:\r");
printf("Satzanfang\n\n");
printf("Folgende Ausgabe demonstriert die Funktion von \\b\n");
printf("12\b34\b56\b78\b9\n");
printf("Dies ist lesbar\n\0und dies nicht mehr."); /* erzeugt ggf. eine Compiler-Warnung */
return 0;
}
Erzeugt auf dem Bildschirm folgende Ausgabe:
Der Zeilenumbruch erfolgt durch die Escape-Sequenz \n Satzanfangen wird ein Wagenrücklauf (carriage return) mit \r erzeugt: Folgende Ausgabe demonstriert die Funktion von \b 13579 Dies ist lesbar