B.13    Antworten und Lösungen zu Kapitel 14

  1. Als Stream wird in C der Datenstrom zwischen dem Programmierer und einer Datei bezeichnet. Ein neuer Stream wird für gewöhnlich beim Öffnen einer Datei angelegt und als Zeiger auf ein Speicherobjekt vom Typ FILE zurückgegeben. Beim Schließen einer Datei wird auch der Stream wieder geschlossen und kann so nicht mehr mit der geschlossenen Datei verwendet werden. Beim Start eines C-Programms stehen immer die drei Standard-Streams stdin (Standardeingabe), stdout (Standardausgabe) und stderr (Standardfehlerausgabe) zur Verfügung.

  2. Die Funktion fopen() öffnet eine Datei in einem bestimmten Modus zum Lesen und/oder Schreiben. Ähnlich funktioniert die Funktion freopen(), nur kann hier zusätzlich noch ein Stream umgelenkt werden. In der Praxis werden mit dieser Funktion für gewöhnlich Standard-Streams umgelenkt, sodass beispielsweise die Standardausgabe in eine Datei oder auf die serielle Schnittstelle umgelenkt werden kann. Dann gibt es noch die Funktion tmpfile(), mit der Sie eine temporäre Datei im Modus "wb+" öffnen können. Die temporäre Datei ist nur zur Laufzeit des Programms gültig und wird bei seiner Beendigung wieder gelöscht.

  3. In Zeile (05) wurde die Datei zum Lesen mit dem Modus "w" geöffnet. Damit wird der komplette ursprüngliche Inhalt gelöscht. Diese Zeile sollten Sie mit dem Lesemodus (beispielsweise "r" oder "r+") öffnen. Hier ein einfaches Beispiel:

    05    fpr = fopen( FILENAME1, "r" );
  4. Das Problem bei dem Listing in diesem Beispiel ist, dass quasi 1.000 FILE-Streams auf einmal geöffnet werden. Der Standard garantiert aber nur FOPEN_MAX offene Streams. Viele Systeme können hier jedoch mehr Streams gleichzeitig geöffnet lassen. Daher kann das Programm in diesem Beispiel auf dem einen System ohne Probleme laufen und auf dem anderen bereits nach FOPEN_MAX offenen Streams abstürzen. Ein Absturz kann natürlich auch in viel »harmloseren« Fällen auftreten, z. B. wenn Sie Ihren Raspberry Pi mit dem PC verbinden und stdout() mit freopen() versehentlich mehr als einmal öffnen. Sie sollten also stets nicht mehr benötigte Streams wieder mit fclose() schließen. Ein Array mit FILE-Zeigern wie in diesem Beispiel ist allerdings auch so überhaupt nicht nötig, denn das vorangehende Programm lässt sich mit einem FILE-Zeiger auch wie folgt verbessern:

    // kap014/loesung001.c
    #include <stdio.h>
    #include <stdlib.h>

    int main(void) {
    int i = 0;
    char filename[255];
    FILE *fp = NULL;
    printf("Programmstart\n");
    while( i < 1000 ) {
    sprintf( filename, "Berechnung%d.txt", i);
    fp = fopen( filename, "w" );
    if( fp != NULL ) {
    fprintf(fp, "Ergebnis der Berechnung Nr.%d", i );
    fclose(fp);
    }
    else {
    fprintf(stderr, "Ergebnis der Berechnung Nr.%d", i);
    }
    ++i;
    }
    return EXIT_SUCCESS;
    }
  5. Hier eine Musterlösung:

    // kap014/loesung002.c
    #include <stdio.h>
    #include <stdlib.h>
    #define CSV "datei.txt"

    int main(void) {
    FILE *fp;
    char wochentag[20];
    int einnahmen, ausgaben;
    int ein_ges=0, aus_ges=0;
    fp = fopen(CSV, "r");
    if(fp == NULL) {
    fprintf(stderr, "Fehler beim Oeffnen\n");
    return EXIT_FAILURE;
    }
    printf("%20s\t%5s\t%5s\n", "Tag", "+", "-");
    while( (fscanf(fp, "%[^;];%d;%d\n",
    wochentag, &einnahmen, &ausgaben)) != EOF) {
    printf("%20s\t%5d\t%5d\n", wochentag, einnahmen, ausgaben);
    ein_ges+=einnahmen;
    aus_ges+=ausgaben;
    }
    printf("\n%20s\t%5d\t%5d", "Gesamt", ein_ges, aus_ges);
    printf("\t = %+d\n", ein_ges-aus_ges);
    return EXIT_SUCCESS;
    }

    Das Programm gibt bei der Ausführung Folgendes aus:

                     Tag    +      -
    Montag 2345 2341
    Dienstag 3245 1234
    Mittwoch 3342 2341
    Donnerstag 2313 2341
    Freitag 2134 6298

    Gesamt 13379 14555 = -1176