Programmieren 1 C Überblick 1. Einleitung 2. Graphische Darstellung von Algorithmen 3. Syntax und Semantik 4. Einstieg in C: Einfache Sprachkonstrukte und allgemeiner Programmaufbau 5. Skalare Standarddatentypen 6. Kontrollfluss 7. Operatoren und Ausdrücke 8. Felder und Zeiger 9. Speicherklassen 10. Strukturen und Unionen 11. Unterprogramm-Techniken (Funktionen) 12. Rekursion Prof. Dr. Björn Dreher Programmieren 1 C 152 Programmieren 1 C Überblick: 13.1 Einleitung 13.3 Datenpufferung 13.4 Die stdio.h Header-Datei 13.5 Fehlerbehandlung 13.8 Wahl der Ein-/Ausgabe-Methode 13.9 Wahlfreier Zugriff 13.11 Zusammenfassung Prof. Dr. Björn Dreher Programmieren 1 C 153
13.1 Einleitung Jedem Algorithmus liegen bestimmte Kontroll- und Datenstrukturen zugrunde Der Kontrollmechanismus des Programms manipuliert die Eingabe-Daten, so dass die gewünschten Ausgabe-Daten entstehen Alle bisher kennen gelernten Datentypen sind interner Natur Existieren nur während der Laufzeit des Programms Ist das Programm zu Ende, sind die Daten weg Prof. Dr. Björn Dreher Programmieren 1 C 154 13.1 Einleitung Will man die Daten auch über längere Zeit zu Verfügung haben, muss man sie irgendwie permanent speichern Diskette, Festplatte, andere Datenträgern (Magnetband, CD- ROM, etc.) Zuvor müssen die Daten jedoch in eine geeignete Struktur gebracht werden und zu einer logischen Einheit zusammengefasst werden Eine solche logische Einheit nennt man Datei, im Englischen File (d.h. Ordner oder Karteikasten) Prof. Dr. Björn Dreher Programmieren 1 C 155
13.1 Einleitung Im Gegensatz zu dem bisher kennen gelernten Datentyp Array ist es bei einer Datei nicht notwendig, von vornherein die Anzahl der Komponenten festzulegen Man kann in eine Datei so viele Sätze schreiben, wie das Speichermedium (oder der Systemadministrator) Platz zur Verfügung stellt Die Datei ist die allgemeinste und mächtigste Ablageform von Daten auf einem Speichermedium Durch geeignete interne Struktur und Verknüpfung mehrerer Dateien erhält man Datenbanken Prof. Dr. Björn Dreher Programmieren 1 C 156 Programmieren 1 C Überblick: 13.1 Einleitung 13.3 Datenpufferung 13.4 Die stdio.h Header-Datei 13.5 Fehlerbehandlung 13.8 Wahl der Ein-/Ausgabe-Methode 13.9 Wahlfreier Zugriff 13.11 Zusammenfassung Prof. Dr. Björn Dreher Programmieren 1 C 157
Problem beim Einbinden von Datei-Ein-/Ausgabeoperationen (File I/O) in eine Programmiersprache Abhängigkeiten vom Betriebssystem ANSI-konforme C-Laufzeitbibliothek stellt an die 40 Funktionen zur Ein- und Ausgabe zur Verfügung. Verwenden alle den sog. buffered I/O, verwenden also einen internen Zwischenpuffer zur Ein- und Ausgabe In C kein Unterschied bezüglich des möglichen Ein-/ Ausgabegerätes Jegliche Ein-/Ausgabe verläuft über sog. streams (etwa: Textstrom), die mit dem Gerät oder der Datei verknüpft sind Geräteunabhängige Ein-/Ausgabe Prof. Dr. Björn Dreher Programmieren 1 C 158 stream: Geordnete Sequenz von Bytes Quasi ein 1-dimensionales Array von Charactern Lesen und Schreiben bedeutet Lesen und Schreiben von bzw. in den stream Bevor Ein-/Ausgabe-Operation möglich ist: Ein stream muss mit der Datei oder dem Gerät verknüpft werden. Definition eines Zeigers auf eine Struktur vom Datentyp FILE Struktur ist in stdio.h definiert Enthält mehrere Komponenten, z.b. für Dateinamen oder Art des Zugriffes sowie Zeiger auf das nächste Zeichen im Datenstrom (file position indicator) Prof. Dr. Björn Dreher Programmieren 1 C 159
Zeiger auf diese Datenstruktur: Sog. file pointer Datentyp FILE* Einzige Angriffspunkt für jegliche Ein-/Ausgabe Wird durch die Funktion fopen() mit einem Wert belegt file position indicator gibt an, von welcher Stelle in dem stream das nächste Zeichen gelesen oder an welche Stelle das nächste Zeichen geschrieben wird Ein Programm kann mehrere streams zur gleichen Zeit offen haben Prof. Dr. Björn Dreher Programmieren 1 C 160 Standardstreams Drei streams sind standardmäßig in jedem C-Programm geöffnet: stdin, stdout und stderr Normalerweise sind sie mit Tastatur bzw. Bildschirm verbunden. printf() schreibt nach stdout, scanf() liest von stdin. Mit den Funktionen fprintf() und fscanf() kann man in gleicher Weise mit Dateien oder externen Geräten kommunizieren. Prof. Dr. Björn Dreher Programmieren 1 C 161
Text- und Binärformat Zwei unterschiedlichen Zugriffs-Formate Text oder binär (text oder binary) Textstrom: Kette von Zeichen aufgeteilt in Zeilen Ende einer Zeile durch newline Character dargestellt Physikalisch können Daten anders gespeichert sein Für Benutzer ist Zeilenende = newline Zeichen Dadurch sind C-Textströme für Programmierer auch auf verschiedenen Systemen identisch handhabbar Dennoch können solche Dateien, insbesondere wenn sie Sonderzeichen enthalten, nicht immer hundertprozentig portabel sein Die oben erwähnten drei Standard streams werden als Textströme geöffnet Prof. Dr. Björn Dreher Programmieren 1 C 162 Text- und Binärformat (fortgesetzt) Binärformat: Daten werden so geschrieben, wie sie im Rechner (z.b. in einer Datenstruktur) gespeichert sind Abhängig von Darstellung der einzelnen Datentypen bei bestimmter Rechnerarchitektur Allgemein nicht leicht portabel Prof. Dr. Björn Dreher Programmieren 1 C 163
Programmieren 1 C Überblick: 13.1 Einleitung 13.3 Datenpufferung 13.4 Die stdio.h Header-Datei 13.5 Fehlerbehandlung 13.8 Wahl der Ein-/Ausgabe-Methode 13.9 Wahlfreier Zugriff 13.11 Zusammenfassung Prof. Dr. Björn Dreher Programmieren 1 C 164 13.3 Datenpufferung Datenpufferung Engl.: buffering Reduktion der physikalischen Zugriffe auf das Ein-/Ausgabegerät Wird von allen Betriebsystemen durchgeführt Zugriff auf 512 oder 1024 Bytes große Blöcke Die C-Laufzeitbibliothek schiebt eine weitere Pufferungsebene dazwischen Zwei Ausprägungen: Zeilenpufferung und Blockpufferung. Im ersten Fall dient der newline Character als Pufferungsgrenze Im zweiten Fall wird immer mit einer festen Blockgröße gearbeitet Prof. Dr. Björn Dreher Programmieren 1 C 165
13.3 Datenpufferung Datenpufferung (fortgesetzt) Man kann mit Hilfe der Funktion fflush() erzwingen, dass der Ausgabepuffer zu dem Gerät hin geleert wird Durch Setzen bestimmter Parameter in der Laufzeitbibliothek kann die Pufferung weiter beeinflusst werden Z.B. ist es möglich durch Setzen der Puffergröße auf 0 die Pufferung ganz auszuschalten (unbuffered I/O) Prof. Dr. Björn Dreher Programmieren 1 C 166 Programmieren 1 C Überblick: 13.1 Einleitung 13.3 Datenpufferung 13.4 Die stdio.h Header-Datei 13.5 Fehlerbehandlung 13.8 Wahl der Ein-/Ausgabe-Methode 13.9 Wahlfreier Zugriff 13.11 Zusammenfassung Prof. Dr. Björn Dreher Programmieren 1 C 167
13.4 Die stdio.h Header-Datei Hier liegen alle wesentlichen I/O-bezogenen Definitionen: FILE Struktur Nützliche Makrokonstanten, wie stdin, stdout und stderr Definition EOF, die von vielen I/O-Funktionen zurückgegeben wird, wenn das Ende der Datei (End-of-File) erreicht ist Früher war hier auch der Null-Pointer Wert NULL definiert Nach ANSI ist dieser Wert jetzt in stddef.h definiert. Prof. Dr. Björn Dreher Programmieren 1 C 168 Programmieren 1 C Überblick: 13.1 Einleitung 13.3 Datenpufferung 13.4 Die stdio.h Header-Datei 13.5 Fehlerbehandlung 13.8 Wahl der Ein-/Ausgabe-Methode 13.9 Wahlfreier Zugriff 13.11 Zusammenfassung Prof. Dr. Björn Dreher Programmieren 1 C 169
13.5 Fehlerbehandlung Fehlerbehandlung bei Ein-/Ausgabe Jede I/O-Funktion liefert im Fehlerfall einen besonderen Wert zurück (Siehe Dokumentation) Zwei Funktionen erlauben es, die End-of-File- und Error-Flags eines streams abzufragen: feof() und ferror() Bei Initialisieren eines streams werden diese Flags zurückgesetzt, später aber nie wieder automatisch Dazu dient die Funktion clearerr(). Prof. Dr. Björn Dreher Programmieren 1 C 170 13.5 Fehlerbehandlung Ein Beispiel /* Return stream status flags. * Two flags are possible: EOF and ERROR */ #include <stdio.h> #define EOF_FLAG 1 #define ERR_FLAG 2 char stream_stat( FILE *fp ) char stat = 0; if (ferror( fp )) stat = ERR_FLAG; /* Bitwise inclusive OR */ if (feof( fp )) stat = EOF_FLAG; /* Bitwise inclusive OR */ clearerr(fp); return stat; Prof. Dr. Björn Dreher Programmieren 1 C 171
13.5 Fehlerbehandlung errno Schlimmes Rudiment aus der Unix-Welt Globale(!) Integer-Variable errno, definiert in errno.h, Wird von einigen (wenigen) I/O-Funktionen benutzt (mehr von mathematischen Funktionen) s. Dokumentation Verwendung möglichst vermeiden! Prof. Dr. Björn Dreher Programmieren 1 C 172 Programmieren 1 C Überblick: 13.1 Einleitung 13.3 Datenpufferung 13.4 Die stdio.h Header-Datei 13.5 Fehlerbehandlung 13.8 Wahl der Ein-/Ausgabe-Methode 13.9 Wahlfreier Zugriff 13.11 Zusammenfassung Prof. Dr. Björn Dreher Programmieren 1 C 173
Öffnen von Dateien Öffnen mit der Funktion fopen() Zwei Parameter: Dateiname Zugriffsmodus Es gibt zwei Sätze von Zugriffsmodi, einen für Textströme und einen für binäre Ströme, wobei die binären Modi sich lediglich durch ein nachgestelltes b unterscheiden. Prof. Dr. Björn Dreher Programmieren 1 C 174 fopen() Text-Zugriffsmodi Kürzel "r" "w" "a" "r+" "w+" "a+" Bedeutung Öffne existierende Textdatei zum Lesen. Lesen beginnt am Anfang der Datei. Erzeuge eine neue Textdatei zum Schreiben. Existiert Datei bereits, wird sie auf Länge 0 abgeschnitten. Der file position indicator steht zunächst am Anfang der Datei. Öffne existierende Textdatei im append Modus. Es kann nur ab dem Ende der Datei weitergeschrieben werden. Öffne existierende Textdatei zum Lesen und Schreiben. Der file position indicator steht zunächst am Anfang der Datei. Erzeuge eine neue Textdatei zum Schreiben und Lesen. Existiert die Datei bereits, wird sie auf Länge 0 abgeschnitten. Der file position indicator steht zunächst am Anfang der Datei. Öffne existierende Textdatei oder erzeuge eine neue im append Modus. Es kann von überall gelesen werden, es kann nur ab dem Ende der Datei geschrieben werden. Prof. Dr. Björn Dreher Programmieren 1 C 175
Auswirkungen der verschiedenen Modi r w a r+ w+ a+ Datei muss existieren * * Alte Datei wird auf Länge 0 beschnitten * * Stream kann gelesen werden * * * * Stream kann geschrieben werden * * * * * Stream kann nur am Ende geschrieben werden * * fopen() gibt als Funktionswert den file pointer zurück Prof. Dr. Björn Dreher Programmieren 1 C 176 Beispiel #include <stddef.h> #include <stdio.h> /* ---- Open file named "test" with read access ----- */ FILE *open_test() /* Returns a pointer to opened FILE */ FILE *fp; fp = fopen ("test", "r"); if (fp == NULL) fprintf(stderr, "Error opening file test\n"); return fp; Das Öffnen und Testen etwas C-typisch knapper: if ((fp = fopen ("test", "r")) == NULL) fprintf(stderr, "Error opening file test\n"); Prof. Dr. Björn Dreher Programmieren 1 C 177
Allgemeinere Funktion Öffnen einer beliebigen Datei in einem beliebigen Modus: #include <stddef.h> #include <stdio.h> FILE *open_file(char *file_name, char *access_mode) FILE *fp; if ((fp = fopen(file_name, access_mode)) == NULL) fprintf(stderr, "Error opening file %s with access" "mode %s\n", file_name, access_mode); return fp; Achtung: Die doppelte Klammerung um ((fp = fopen(...)) ist notwendig, da der == -Operator einen höheren Vorrag als = hat! Prof. Dr. Björn Dreher Programmieren 1 C 178 Zugehörige main-funktion #include <stddef.h> #include <stdio.h> int main(void) extern FILE *open_file(char *file_name, char *access_mode) if (open_file("test", "r") == NULL) exit(1);... Schließen einer Datei fclose(fp); Man sollte dies auch möglichst immer tun Prof. Dr. Björn Dreher Programmieren 1 C 179
Programmieren 1 C Überblick: 13.1 Einleitung 13.3 Datenpufferung 13.4 Die stdio.h Header-Datei 13.5 Fehlerbehandlung 13.8 Wahl der Ein-/Ausgabe-Methode 13.9 Wahlfreier Zugriff 13.11 Zusammenfassung Prof. Dr. Björn Dreher Programmieren 1 C 180 Lesen und Schreiben ist in 3 verschiedenen Granularitäten möglich: Zeichen, Zeile, Block Die folgenden Beispiele realisieren eine Funktion, die eine Datei in eine andere kopiert, auf diese drei verschiedenen Weisen Prof. Dr. Björn Dreher Programmieren 1 C 181
Zeichenweises I/O Vier Funktionen getc() fgetc() putc() fputc() Makro, der ein Zeichen aus dem stream liest Dasselbe als Funktion Makro, der ein Zeichen in den stream schreibt Dasselbe als Funktion Vorsicht mit Makros! Aber oft schneller Prof. Dr. Björn Dreher Programmieren 1 C 182 Zeichenweises I/O: Beispiel #include <stddef.h> #include <stdio.h> #define FAIL 0 #define SUCCESS 1 int copyfile(char *infile, char *outfile) FILE *fp1, *fp2; if ((fp1 = fopen( infile, "rb" )) == NULL) return FAIL; if ((fp2=fopen ( outfile, "wb" )) == NULL) fclose( fp1 ); return FAIL; while (!feof( fp1 )) putc( getc( fp1 ), fp2 ); fclose( fp1 ); fclose( fp2 ); return SUCCESS; Prof. Dr. Björn Dreher Programmieren 1 C 183
Zeichenweises I/O: Beispiel (fortgesetzt) Dateien im Binär-Modus geöffnet Interne Details und Strukturen nicht von Interesse Binär-Modus: Funktionswert von getc() kann nicht benutzt werden, um EOF zu detektieren Jeder binäre Wert, der der Konstanten EOF entspricht, würde die Schleife beenden Aufruf von feof() ist in allen Fällen eindeutig Prof. Dr. Björn Dreher Programmieren 1 C 184 Zeilenweises I/O Zwei Funktionen: fgets() und fputs() Der Prototyp von fgets(): char *fgets(char *s, int n, FILE *stream); mit s: Zeiger auf das erste Element eines Arrays, in das die Zeile geschrieben wird n: Maximale Anzahl zu lesender Zeichen stream: Input Stream Zeiger Prof. Dr. Björn Dreher Programmieren 1 C 185
Zeilenweises I/O: fgets() char *fgets(char *s, int n, FILE *stream); Liest so viele Zeichen bis ein newline Zeichen gefunden, EOF oder die maximale Anzahl der zu lesenden Zeichen erreicht ist Speichert im Puffer auch newline Character Liest maximal n-1 Zeichen Schließt Puffer mit \0 ab Gibt NULL zurück, wenn EOF gefunden wurde, sonst denselben Zeiger wie das erste Argument Prof. Dr. Björn Dreher Programmieren 1 C 186 Zeilenweises I/O: Unser Beispiel #include <stddef.h> #include <stdio.h> #define FAIL 0 #define SUCCESS 1 #define LINESIZE 100 int copyfile( char *infile, char *outfile ) FILE *fp1, *fp2; char line[linesize]; Öffnen im Textmodus if ((fp1 = fopen( infile, "r" )) == NULL) return FAIL; if ((fp2 = fopen( outfile, "w" )) == NULL) fclose( fp1 ); return FAIL; while (fgets( line, LINESIZE, fp1 )!= NULL) fputs( line, fp2 ); fclose( fp1 ); fclose( fp2 ); return SUCCESS; Prof. Dr. Björn Dreher Programmieren 1 C 187
Blockweises I/O: Zwei Funktionen: fread() und fwrite() Prototyp von fread(): size_t *fread(void *ptr, size_t size, size_t count, FILE *stream); mit ptr: Zeiger auf das erste Element eines untypisierten Arrays, in das die Zeile geschrieben wird size: Anzahl Zeichen pro Element count: Anzahl zu lesender Elemente stream: Input Stream Zeiger Resultat: Tatsächlich gelesene Anzahl von Elementen Sollte derselbe Wert wie der des 3. Parameters sein, falls nicht EOF erreicht wurde oder ein Fehler auftrat fwrite() besitzt dieselbe Parameterversorgung, aber schreibt natürlich in den stream Prof. Dr. Björn Dreher Programmieren 1 C 188 Blockweises I/O: Unser Beispiel #include <stddef.h> #include <stdio.h> #define FAIL 0 #define SUCCESS 1 #define BLOCKSIZE 512 typedef char DATA; int copyfile(char *infile, char *outfile) FILE *fp1, *fp2; DATA block[blocksize]; int num_read; if ((fp1 = fopen( infile, "rb" )) == NULL) printf( "Error opening file %s for input.\n", infile ); return FAIL;... Prof. Dr. Björn Dreher Programmieren 1 C 189
Blockweises I/O: Unser Beispiel (fortgesetzt) if ((fp2 = fopen( outfile, "wb" )) == NULL) printf( "Error opening file %s for output.\n", outfile ); fclose( fp1 ); return FAIL; while ((num_read = fread( block, sizeof(data), BLOCKSIZE, fp1 )) > 0) fwrite( block, sizeof(data), num_read, fp2 ); fclose( fp1 ); fclose( fp2 ); if (ferror( fp1 )) printf( "Error reading file %s\n", infile ); return FAIL; return SUCCESS; Prof. Dr. Björn Dreher Programmieren 1 C 190 Programmieren 1 C Überblick: 13.1 Einleitung 13.3 Datenpufferung 13.4 Die stdio.h Header-Datei 13.5 Fehlerbehandlung 13.8 Wahl der Ein-/Ausgabe-Methode 13.9 Wahlfreier Zugriff 13.11 Zusammenfassung Prof. Dr. Björn Dreher Programmieren 1 C 191
13.8 Wahl der Ein-/Ausgabe-Methode Kriterien: Von der Geschwindigkeit her sind die Makros putc() und getc() normalerweise am schnellsten Oft besitzen Betriebssysteme jedoch direkte Schnittstellen für Block I/O, die sehr effizient sind Diese sind jedoch üblicherweise nicht in die C- Laufzeitbibliothek integriert Ggf. muss man sie direkt aufrufen. Textdateien sollten im Textmodus geöffnet werden, Dateien mit binären Daten im binären Modus Anderer Aspekt: Einfachheit und Lesbarkeit des Quelltextes Will man z.b. eine zeilenweise Auswertung einer Datei durchführen, dann sind die (langsameren) Funktionen fgets() und fputs() die bessere Wahl... Prof. Dr. Björn Dreher Programmieren 1 C 192 13.8 Wahl der Ein-/Ausgabe-Methode Zeilenweise Verarbeitung: #include <stdio.h> #include <stddef.h> #define MAX_LINE_SIZE 120 /* ---------- Zähle die Zeilen einer Datei ------------ */ int lines_in_file(file *fp) char buf[max_line_size]; int line_num = 0; rewind(fp); /* Moves the file position indicator * to the beginning of the file. */ while (fgets(buf, MAX_LINE_SIZE, fp)!= NULL) line_num++; return line_num; Prof. Dr. Björn Dreher Programmieren 1 C 193
Programmieren 1 C Überblick: 13.1 Einleitung 13.3 Datenpufferung 13.4 Die stdio.h Header-Datei 13.5 Fehlerbehandlung 13.8 Wahl der Ein-/Ausgabe-Methode 13.9 Wahlfreier Zugriff 13.11 Zusammenfassung Prof. Dr. Björn Dreher Programmieren 1 C 194 13.9 Wahlfreier Zugriff Wahlfreier Zugriff, engl.: Random Access Für Anwendungen, wo (wahlfrei) von einer bestimmten Stelle der Datei gelesen werden soll Funktionen fseek() und ftell() fseek() bewegt den file position indicator zu bestimmtem Zeichen im Strom: int fseek(file *stream, long int offset, int whence); Die Argumente sind: stream der File Pointer offset ein positiver oder negativer Offset in Characters whence von wo aus wird der Offset gerechnet (whence = woher) Mögliche Werte für whence sind SEEK_SET vom Anfang der Datei SEEK_CUR von der aktuellen Stelle des file position indicators SEEK_END vom Ende der Datei (EOF Position) Prof. Dr. Björn Dreher Programmieren 1 C 195
13.9 Wahlfreier Zugriff Beispiel: status = fseek(fp, 10, SEEK_SET); positioniert den file position indicator zum Zeichen 10 im Strom Auch hier wird ab 0 gezählt Es wird 10 Zeichen ab dem Zeichen 0 vorwärts positioniert, also auf das 11. Zeichen Wenn alles o.k. ist, gibt fseek() eine 0 zurück! offset: Für binäre Ströme positiver oder negativer Wert; darf nicht aus dem Bereich der Datei herausführen Für Textströme muss whence den Wert SEEK_SET haben und offset 0 sein oder einen Wert besitzen, der von ftell() zurückgegeben wurde Prof. Dr. Björn Dreher Programmieren 1 C 196 13.9 Wahlfreier Zugriff ftell(): Hat nur den File Pointer als Argument Gibt den aktuellen Wert des file position indicators zurück Hiermit kann man sich eine Position in der Datei merken, zu der man später wieder hinpositionieren will: cur_pos = ftell(fp); if (search(string) == FAIL) fseek(fp, cur_pos, SEEK_SET); Prof. Dr. Björn Dreher Programmieren 1 C 197
Programmieren 1 C Überblick: 13.1 Einleitung 13.3 Datenpufferung 13.4 Die stdio.h Header-Datei 13.5 Fehlerbehandlung 13.8 Wahl der Ein-/Ausgabe-Methode 13.9 Wahlfreier Zugriff 13.11 Zusammenfassung Prof. Dr. Björn Dreher Programmieren 1 C 198 Schreiben und Lesen einer binären Datei #include <stdlib.h> #include <stdio.h> int main(void) /*---------------------------------------------------------+ * Dieses Programm liest eine Zahl von Datensätzen von der * Tastatur-Eingabe und schreibt sie in eine Datei im * Laufwerk a:. Nach beendeter Eingabe werden zuerst die * männlichen Einträge, dann die weiblichen auf dem Bild- * schirm gelistet. *---------------------------------------------------------*/ typedef struct char name[20]; int geschlecht; PERSON; FILE *datei; PERSON satz; char eingabe[5], antwort[5]; Datenstruktur eines Dateisatzes if ((datei = fopen("a:\\person.dat", "wb")) == NULL) printf("fehler beim Öffnen der Datei"); exit(1); Öffne binar zum Schreiben Prof. Dr. Björn Dreher Programmieren 1 C 199
Schreiben und Lesen einer binären Datei (fortgesetzt) do printf("name: "); scanf("%s", satz.name); printf("männlich oder weiblich (M/W)? "); scanf("%s", eingabe); switch (eingabe[0]) /* Wandle Eingabe in Zieltyp um */ case 'M': case 'm': satz.geschlecht = 1; break; case 'W': case 'w': satz.geschlecht = 2; break; if (fwrite(&satz, sizeof(satz), 1, datei)!= 1) printf("fehler beim Schreiben\n"); exit(2); printf("\nweiteren Satz eingeben (J/N)? "); scanf("%s", antwort); while ((antwort[0] == 'J') (antwort[0] == 'j')); fclose(datei); Schreibe einen Block der Größe eines Satzes Prof. Dr. Björn Dreher Programmieren 1 C 200 Schreiben und Lesen einer binären Datei (fortgesetzt) Öffne binar zum... Lesen /* ------------------- Ausgabe 'männlich' ---------------- */ printf("\nmännlich:\n"); if ((datei = fopen("a:\\person.dat", "rb")) == NULL) printf("fehler beim 1. Öffnen der Datei zum Lesen"); exit(3); while (fread(&satz, sizeof(satz), 1, datei) == 1) if (satz.geschlecht = 1) printf("%s\n", satz.name); fclose(datei);... Lies einen Block der Größe eines Satzes Prof. Dr. Björn Dreher Programmieren 1 C 201
Schreiben und Lesen einer binären Datei (fortgesetzt)... /* ------------------- Ausgabe 'weiblich' ---------------- */ printf("\nweiblich:\n"); if ((datei = fopen("a:\\person.dat", "rb")) == NULL) printf("fehler beim 2. Öffnen der Datei zum Lesen"); exit(4); while (fread(&satz, sizeof(satz), 1, datei) == 1) if (satz.geschlecht = 2) printf("%s\n", satz.name); fclose(datei); return 0; Prof. Dr. Björn Dreher Programmieren 1 C 202 Binäre Datei mit folgender Satzstruktur #define NAME_LEN 19 typedef char NAME[NAME_LEN]; typedef struct int day; int month; int year; DATE; typedef struct NAME name; char ssnum[11]; DATE bdate; VITALSTAT; Prof. Dr. Björn Dreher Programmieren 1 C 203
Binäre Datei enthält unsortierte Einträge Sortierte Ausgabe soll über wahlfreien Zugriff auf Datensätze erfolgen Reihenfolge spezifiziert ein Index-Array: typedef struct int index; NAME name; INDEX; 1 2 3 10 Schulze Meier Müller Arnold Lesen in der Reihenfolge: 10,..., 2, 3, 1 Sortierung nach Name, Index gibt zu lesenden Satz an Prof. Dr. Björn Dreher Programmieren 1 C 204 Hauptprogramm Öffne binär zum Lesen INDEX index[max_rec_num];... if((data_file = fopen(filename, "rb")) == NULL) printf("error opening file %s.\n", filename); exit(2); Fülle index num_recs_read = get_records(data_file, index, MAX_REC_NUM); sort_index(index, num_recs_read); Sortiere index printf("unsorted...\n\n"); print_records(data_file, num_recs_read); printf("sorted...\n\n"); print_indexed_records(data_file, index, num_recs_read);... Gib sortiert aus Prof. Dr. Björn Dreher Programmieren 1 C 205
get_records() int get_records(file *data_file, INDEX names_index[], int max_rec_num) int k, offset = 0, counter = 0, blocks_read = 1; for (k = 0; blocks_read == 1 && counter < max_rec_num; k++) blocks_read = fread(names_index[k].name, NAME_LEN, 1, data_file); if (blocks_read == 1) offset += sizeof(vitalstat); fseek(data_file, offset, SEEK_SET); counter++; return counter; Lies in Komponente name der Struktur INDEX Lesen war erfolgreich Prof. Dr. Björn Dreher Programmieren 1 C 206 sort_index() void sort_index(index names_index[], int index_count) int j; int compare_func(); /* Defined later */ /* Assign values to the index field of each structure */ for (j = 0; j < index_count; j++) names_index[j].index = j; Größe eines Arrayelementes qsort(names_index, index_count, sizeof(index), compare_func); return; Zeiger auf Funktion int compare_func(index *p, INDEX *q) return strcmp(p->name, q->name); Vergleichsfunktion Prof. Dr. Björn Dreher Programmieren 1 C 207
print_indexed_records() void print_indexed_records(file *data_file, INDEX index[], int index_count) VITALSTAT vs; int j; Positioniere auf Index for (j = 0; j < index_count; j++) if(fseek(data_file, sizeof(vitalstat)*index[j].index, SEEK_SET) ) exit(3); Lies aktuellen Satz fread(&vs, sizeof(vitalstat), 1, data_file); printf("%20s: %2d.%2d.%4d, %12s\n", vs.name, vs.bdate.day, vs.bdate.month, vs.bdate.year, vs.ssnum); Prof. Dr. Björn Dreher Programmieren 1 C 208 print_records() void print_records(file *data_file, int index_count) VITALSTAT vs; int j; Positioniere an Anfang der Datei rewind(data_file); for (j = 0; j < index_count; j++) Lies sequentiell fread(&vs, sizeof(vitalstat), 1, data_file); printf("%20s: %2d.%2d.%4d, %12s\n", vs.name, vs.bdate.day, vs.bdate.month, vs.bdate.year, vs.ssnum); Prof. Dr. Björn Dreher Programmieren 1 C 209
Programmieren 1 C Überblick: 13.1 Einleitung 13.3 Datenpufferung 13.4 Die stdio.h Header-Datei 13.5 Fehlerbehandlung 13.8 Wahl der Ein-/Ausgabe-Methode 13.9 Wahlfreier Zugriff 13.11 Zusammenfassung Prof. Dr. Björn Dreher Programmieren 1 C 210 13.11 Zusammenfassung Ein-/Ausgabe mit stdin oder stdout Funktion getchar() gets() printf() putchar() puts() scanf() Beschreibung Liest nächstes Zeichen von stdin. Identisch mit getc(stdin) Liest Zeichen von stdin bis newline oder eof angetroffen Gibt ein oder mehrere Werte entsprechend Formatierungsangaben des Anwenders nach stdout aus Gibt ein Zeichen nach stdout aus. Identisch mit putc(stdout) Gibt einen String von Zeichen nach stdout aus. Fügt ein newline ans Ende Liest ein oder mehrere Werte von stdin, wobei jeder gemäß den Formatierungsregeln interpretiert wird Prof. Dr. Björn Dreher Programmieren 1 C 211
13.11 Zusammenfassung Fehlerbehandlung Funktion clearerr() feof() ferror() Beschreibung Fehlerflag (errno) und EOF-Flag des entsprechenden streams werden zurückgesetzt Prüft, ob während der vorigen I/O-Operation EOF gefunden wurde Gibt einen Fehlerwert zurück (Wert von errno), falls zuvor ein fehler aufgetreten ist, sonst 0 Prof. Dr. Björn Dreher Programmieren 1 C 212 13.11 Zusammenfassung Dateimanagement Funktion remove() rename() tmpfile() tmpname() Beschreibung Löscht eine Datei Benennt eine Datei um Erzeugt eine temporäre binäre Datei Erzeugt einen Namen für eine temporäre Datei Prof. Dr. Björn Dreher Programmieren 1 C 213
13.11 Zusammenfassung Ein-/Ausgabe mit Dateien Funktion fclose() fflush() fgetc() fgets() fopen() fprintf() fputc() fputs() Beschreibung Schließt eine Datei Leert den Puffer des streams. Datei bleibt geöffnet wie getc(), aber als Funktion statt Makro implementiert wie gets(), aber von beliebigem stream; weiterhin kann die maxi-male Anzahl der zu lesenden Zeichen angegeben werden Öffnet, evtl. kreiert, Datei und verknüpft sie mit einem stream wie printf(), jedoch nach beliebigem stream wie putc(), aber als Funktion statt Makro implementiert wie puts(), aber nach beliebigem stream; weiterhin wird kein newline in den stream geschrieben Prof. Dr. Björn Dreher Programmieren 1 C 214 13.11 Zusammenfassung Ein-/Ausgabe mit Dateien (fortgesetzt) Funktion fread() freopen() fscanf() fseek() ftell() fwrite() getc() putc() ungetc() Beschreibung Liest einen Block von Daten von einem stream Schließt einen stream und öffnet ihn mit einer neuen Datei (z.b. Umdefinition von stdin) wie scanf(), jedoch von beliebigem stream Positioniere wahlfrei in Datei Liefert Wert des file position indicators zurück Schreibt einen Block von Daten in einen stream Liest ein Zeichen von einem stream Schreibt ein Zeichen in einen stream Schreibt ein Zeichen in einen stream zurück Prof. Dr. Björn Dreher Programmieren 1 C 215