Input/Output
stdio-Bibliothek
In C sind die Eingabe- und Ausgabeoperationen nicht Teil der Sprache, sondern werden durch eine Bibliothek zur Verfügung gestellt. Da diese Bibliothek im C-Standard definiert wird, sollte sie auf allen Plattformen und bei allen C-Compilern zur Verfügung stehen. Ausnahmen sind eingebettete Systeme, die kein Input/Output unterstützen.
Dreh und Angelpunkt der I/O in C ist die stdio-Bibliothek, die eine ganze Reihe von Funktionen anbietet.
- Eingabe/Ausgabe wird über die stdio-Bibliothek realisiert
#include <stdio.h>- wird automatisch gelinkt
- Definiert den Typ
FILE*und Funktionen für Dateizugriff - Definiert
stdin,stdout,stderr
stdin, stdout und stderr sind vordefinierte FILE-Objekte, die den Zugriff auf die Standard-Ein- und -Ausgabe ermöglichen.
Neben den Funktionen in stdio.h, die im C-Standard definiert werden, gibt es eine Reihe von korrespondierenden Low-Level-I/O-Funktionen, die vom POSIX-Standard festgelegt werden. Diese Funktionen sind näher am Betriebssystem und bieten weniger Komfort. Außerdem sind sie nur auf Systemen verfügbar, die den POSIX-Standard unterstützen, wozu allerdings die relevanten Betriebssysteme gehören. Deswegen sollte man prinzipiell die C-Standard-Funktionen benutzen und die Low-Level-Funktionen ignorieren.
Beispiele Low-Level-Funktionen sind:
int open(const char *pathname, int flags, mode_t mode);int creat(const char *pathname, mode_t mode);int close(int fd);
Ken Thompson, einer der Erfinder von Unix, wurde einmal gefragt, was er heute anders machen würde, wenn er Unix noch einmal entwickeln dürfte. Seine Antwort war „I'd spell creat with an e.“
Dateien öffnen und schließen
FILE fopen(const char *path, const char *mode)
- öffnet die Datei
path - Modus (
mode) "r": Lesen"r+": Lesen und schreiben (ab Anfang)"w": Anlegen und schreiben (ab Anfang)"w+": Anlegen, lesen und schreiben (ab Anfang)"a": Schreiben (am Ende anhängen)"a+": Lesen und schreiben (am Ende anhängen)- bei Erfolg wird ein
FILE*zurückgegeben, im FehlerfallNULL
int fclose(FILE *stream)
- schließt die Datei
stream - 0 bei Erfolg,
EOFim Fehlerfall
FILE* handle = fopen("/tmp/file", "r");
if (handle == NULL) {
/* Fehler */
exit(0);
}
/* Mit Datei arbeiten */
if (fclose(handle)) {
/* Fehler beim Schließen */
}
Die Standardbibliothek spricht hier von Streams und nicht Dateien, weil die Metoden auch auf andere Arten von I/O angewendet werden können, z. B. die Console, die keine Datei ist.
Zeichen-I/O
Funktionen für den Zugriff auf einzelne Zeichen. Alle Funktionen geben EOF zurück, wenn Datei/stream zu Ende ist oder ein Fehler auftritt
int getchar()
Liest das nächste Zeichen vonstdinint fgetc(FILE *in)
List das nächste Zeichen aus Dateiinint putchar(int c)
Schreibt ein Zeichen aufstdoutint fputc(int c, FILE *out)
Schreibt ein Zeichen in Dateiout
Bemerkenswert ist aber die Tatsache, dass die Funktion getchar() ein int als Rückgabetyp hat und kein char, obwohl ein Stream byteweise gelesen wird. Der größere Datentyp ist nötig, da durch ein EOF signalisiert wird, dass der Stream zu Ende ist. EOF hat den Wert -1. Da aber -1 ein gültiger char-Wert ist, hat man hier den größeren Datentyp nehmen müssen. Aus diesem Grund ist es falsch den Rückgabewert von getchar() vor dem Vergleich mit EOF zu casten. Erst muss mit EOF (als int) verglichen werden, dann gecastet, sonst bricht der Lesevorgang möglicherweise zu früh ab, nämlich wenn in den Daten zufällig ein 0xFF vorkommt, das vorzeichenbehaftet einer -1 entspricht.
int c;
FILE* fd = fopen("test.txt", "r");
while ((c = fgetc(fd)) != EOF) {
printf("%c", (unsigned char) c);
}
Dass die putchar()- und fputc()-Funktionen auch einen int und kein unsigned char nehmen, dient der Bequemlichkeit des Programmierers, der sich so teilweise einen Cast ersparen kann.
Zeilen-I/O
Anstatt einzelne Zeichen kann man auch direkt auf Zeilen arbeiten. Die entsprechenden Funktionen akzeptieren bzw. liefern Zeichenketten in Form von char*.
Funktionen für den Zugriff auf Zeilen
char *fgets(char *buf, int size, FILE *in)- liest die nächste Zeile von
ininbuf - kehrt bei
'\n'zurück oder wennsize - 1Zeichen gelesen wurden '\n'selbst wird auch zurückgegeben- gibt Zeiger auf
bufzurück oderNULLim Fehlerfall - auf keinen Fall
gets(char *)verwenden ⇒ Buffer-Overflow int fputs(const char *str, FILE *out)- schreibt den String
strin die Dateiout - stoppt beim
'\0' - gibt die Anzahl der geschriebenen Zeichen zurück, oder
EOFbei Fehler
Formatierte I/O
int fscanf(FILE *in, const char *format, ...)
Analog zuscanfaber für Dateiint fprintf(FILE *out, const char *format, ...)
Analog zusprintfaber für Dateiint printf(const char *format, ...)
⇔fprintf(stdout, format, ...)
fscanf(...) sollte man nicht verwenden. Besser fgets(str, ...) zusammen mit sscanf(str, ...) Von der Console lesen
- Mit
fgets(str, ...)undsscanf(str, ...)kann man Daten von der Konsole lesen
int main() {
char buffer[255];
int zahl;
printf("Bitte geben Sie eine Zahl ein: ");
if (fgets(buffer, 254, stdin) != 0) {
sscanf(buffer, "%d", &zahl);
printf("Die Zahl war %d\n", zahl);
}
}
Bitte geben Sie eine Zahl ein: 62
Die Zahl war 62