Fehlerbehandlung beim Kopieren einer ASCII-Datei

Es ist ein guter Programmierstil, innerhalb eines Programms Abbrüche mit return oder exit zu vermeiden. Der Quellcode gewinnt dadurch an Übersicht. Das hier aufgeführte Beispiel zeigt das Kopieren einer ASCII-Datei, wobei ein besonderer Fokus auf die Fehlerabfrage gelegt wird. Statt bei möglichen Fehlern das Programm abzubrechen wird ein Fehlerindikator gesetzt.


#include <stdio.h>

int main()
{
    char InpFileName[] = "main.c";
    char OutFileName[] = "main.bak";
    FILE *inp=NULL;     /* Zeiger auf Eingabedatei-Struktur */
    FILE *out=NULL;     /* Zeiger auf Ausgabedatei-Struktur */
    char ch;            /* aktuelles Zeichen */
    int Fehler=0;       /* Fehlerindikator */

    /* Erster Schritt: Dateien öffnen */
    if(!Fehler) {
        inp = fopen(InpFileName, "rt");
        if(inp==NULL) {
            printf("Konnte Eingabedatei nicht oeffnen: %s\n", InpFileName);
            Fehler = -1;
        }
    }
    if(!Fehler) {
        out = fopen(OutFileName, "wt");
        if(out==NULL) {
            printf("Konnte Ausgabedatei nicht oeffnen: %s\n", OutFileName);
            Fehler = -2;
        }
    }

    /* Zweiter Schritt: Dateien verarbeiten */
    if(!Fehler) {
        ch = fgetc(inp);
        while(!feof(inp)) {
            fputc(ch, out);
            ch = fgetc(inp);
        }
    }

    /* Dritter Schritt: Dateien schließen */
    if(inp!=NULL) fclose(inp);
    if(out!=NULL) fclose(out);

    return Fehler;
}

Einführung eines Fehlerindikators

Wir führen einen Fehlerindikator ein, der zu jedem Zeitpunkt angibt, ob ein Fehler aufgetreten ist oder nicht. Er wird mit 0 initialisiert (logisch nicht wahr), was soviel bedeutet, dass bisher kein Fehler aufgetreten ist. Sobeld ein Fehler auftritt wird diese Variable auf einen Wert ungleich 0 (logisch wahr) gesetzt.

Nur fortfahren, wenn kein Fehler aufgetreten ist

Im Verlauf des Programms wird an einigen Stellen erst geprüft, ob ein Fehler aufgetreten ist. Nur wenn der Programmlauf bis dahin ohne Fehler erfolgt ist, werden weitere Programmblöcke abgearbeitet.

Fehlercodes setzen

Tritt an einer Stelle im Programm ein Fehler auf, so wird das Programm nicht mit einem return beendet, sondern es wird nur ein Fehlercode gesetzt. Dabei sollte für jeden Fehler ein eindeutiger Wert vergeben werden, damit später über den Fehlercode ggf. speziell auf den Fehler reagiert werden kann.

Fehlercode zurückgeben

Am Ende wird der Fehlercode zurückgegeben. Trat kein Fehler auf, so wird der Wert 0 zurückgegeben. Trat ein Feheler auf, so wird der entsprechende Wert ungleich null zurückgegeben, der bei dem Fehler gesetzt wurde. Ist dieses Programm Teil eines größeren Programms, so kann über den Fehlercode eine angemessene Weiterverarbeitung erfolgen.

Dateizeiger initialisieren

Bei dem Arbeiten mit einem Fehlerindikator muss sicher gestellt werden, dass am Ende die Dateien geschlossen werden. Das wird mit einer einfachen Konvention erreicht: Zeigt ein Zeiger für eine Datei auf einen Wert ungleich NULL, so ist die Datei geöffnet. Zeigt der Zeiger auf NULL, so ist die Datei geschlossen. In diesem Beispiel initialisieren wir von daher die beiden Zeiger für die Dateien mit dem Wert NULL, da sie ja am Anfang noch nicht geöffnet sind.

Dateien schließen

Mit der Konvention: Zeiger auf NULL = Datei geschlossen und Zeiger ungleich NULL = Datei offen kann am Ende des Programms sicher gestellt werden, dass alle offenen Dateien (und nur die offenen Dateien) sicher geschlossen werden. Vor dem Befehl zum Schließen der Datei wir geprüft, ob der zugehörige Zeiger auf einen Wert ungleich NULL zeigt. Auf diese Weise werden nur die offenen Dateien geschlossen. Das gleiche Prinzip kann auch bei der dynamischen Speicherreservierung angewendet werden.

























Seite 18