Rheinwerk Computing < openbook > Rheinwerk Computing - Professionelle Bücher. Auch für Einsteiger.
Professionelle Bücher. Auch für Einsteiger.

Inhaltsverzeichnis
Vorwort
Vorwort des Gutachters
1 Einstieg in C
2 Das erste Programm
3 Grundlagen
4 Formatierte Ein-/Ausgabe mit »scanf()« und »printf()«
5 Basisdatentypen
6 Operatoren
7 Typumwandlung
8 Kontrollstrukturen
9 Funktionen
10 Präprozessor-Direktiven
11 Arrays
12 Zeiger (Pointer)
13 Kommandozeilenargumente
14 Dynamische Speicherverwaltung
15 Strukturen
16 Ein-/Ausgabe-Funktionen
17 Attribute von Dateien und das Arbeiten mit Verzeichnissen (nicht ANSI C)
18 Arbeiten mit variabel langen Argumentlisten – <stdarg.h>
19 Zeitroutinen
20 Weitere Headerdateien und ihre Funktionen (ANSI C)
21 Dynamische Datenstrukturen
22 Algorithmen
23 CGI mit C
24 MySQL und C
25 Netzwerkprogrammierung und Cross–Plattform-Entwicklung
26 Paralleles Rechnen
27 Sicheres Programmieren
28 Wie geht’s jetzt weiter?
A Operatoren
B Die C-Standard-Bibliothek
Stichwort

Buch bestellen
Ihre Meinung?

Spacer
<< zurück
C von A bis Z von Jürgen Wolf
Das umfassende Handbuch
Buch: C von A bis Z

C von A bis Z
3., aktualisierte und erweiterte Auflage, geb., mit CD und Referenzkarte
1.190 S., 39,90 Euro
Rheinwerk Computing
ISBN 978-3-8362-1411-7
Pfeil 16 Ein-/Ausgabe-Funktionen
Pfeil 16.1 Was ist eine Datei?
Pfeil 16.2 Formatierte und unformatierte Ein-/Ausgabe
Pfeil 16.3 Standard-Streams
Pfeil 16.4 Höhere Ein-/Ausgabe-Funktionen
Pfeil 16.5 Datei (Stream) öffnen – »fopen«
Pfeil 16.5.1 Modus für »fopen()«
Pfeil 16.5.2 Maximale Anzahl geöffneter Dateien – »FOPEN_MAX«
Pfeil 16.6 Zeichenweise lesen und schreiben – »getchar()« und »putchar()«
Pfeil 16.6.1 Ein etwas portableres »getch()«
Pfeil 16.7 Zeichenweise lesen und schreiben – »putc()«/»fputc()« und »getc()«/»fgetc()«
Pfeil 16.8 Datei (Stream) schließen – »fclose()«
Pfeil 16.9 Formatiertes Einlesen/Ausgeben von Streams mit »fprintf()« und »fscanf()«
Pfeil 16.10 Standard-Streams in C
Pfeil 16.10.1 Standard-Streams umleiten
Pfeil 16.11 Fehlerbehandlung von Streams – »feof()«, »ferror()« und »clearerr()«
Pfeil 16.12 Gelesenes Zeichen in die Eingabe zurückschieben – »ungetc()«
Pfeil 16.13 (Tastatur-)Puffer leeren – »fflush()«
Pfeil 16.14 Stream positionieren – »fseek()«, »rewind()« und »ftell()«
Pfeil 16.15 Stream positionieren – »fsetpos()«, »fgetpos()«
Pfeil 16.16 Zeilenweise Ein-/Ausgabe von Streams
Pfeil 16.16.1 Zeilenweise lesen mit »gets()«/»fgets()«
Pfeil 16.16.2 Zeilenweise schreiben mit »puts()«/»fputs()«
Pfeil 16.16.3 Zeilenweise vom Stream einlesen mit »getline()« (nicht ANSI C)
Pfeil 16.16.4 Rezepte für zeilenweises Einlesen und Ausgeben
Pfeil 16.17 Blockweise lesen und schreiben – »fread()« und »fwrite()«
Pfeil 16.17.1 Blockweise lesen – »fread()«
Pfeil 16.17.2 Blockweise schreiben – »fwrite()«
Pfeil 16.17.3 Big Endian und Little Endian
Pfeil 16.18 Datei (Stream) erneut öffnen – »freopen()«
Pfeil 16.19 Datei löschen oder umbenennen – »remove()« und »rename()«
Pfeil 16.19.1 remove()
Pfeil 16.19.2 rename()
Pfeil 16.20 Pufferung einstellen – »setbuf()« und »setvbuf()«
Pfeil 16.20.1 Die Funktion »setbuf()«
Pfeil 16.20.2 Die Funktion »setvbuf()«
Pfeil 16.21 Temporäre Dateien erzeugen – »tmpfile()« und »tmpnam()«
Pfeil 16.21.1 »mkstemp()« – sichere Alternative für Linux/UNIX (nicht ANSI C)
Pfeil 16.22 Fehlerbehandlung
Pfeil 16.22.1 Fehlerausgabe mit »perror()«
Pfeil 16.22.2 Fehlerausgabe mit »strerror()«
Pfeil 16.23 Formatiert in einen String schreiben und formatiert aus einem String lesen – »sscanf()« und »sprintf()«
Pfeil 16.24 Byte- und wide-orientierter Stream
Pfeil 16.25 Ein fortgeschrittenes Thema
Pfeil 16.26 Low-Level-Datei-I/O-Funktionen (nicht ANSI C)
Pfeil 16.26.1 Datei öffnen – »open()«
Pfeil 16.26.2 Datei schließen – »close()«
Pfeil 16.26.3 Datei erzeugen – »creat()«
Pfeil 16.26.4 Schreiben und Lesen – »write()« und »read()«
Pfeil 16.26.5 File-Deskriptor positionieren – »lseek()«
Pfeil 16.26.6 File-Deskriptor von einem Stream – »fileno()«
Pfeil 16.26.7 Stream von File-Deskriptor – »fdopen()«


Rheinwerk Computing - Zum Seitenanfang

16.25 Ein fortgeschrittenes Thema topZur vorigen Überschrift

Mittlerweile haben Sie ja in diesem Buch schon einiges gelernt. Aber irgendwie waren alle Themen doch sehr theoretisch. Ich habe vorwiegend gezeigt, wie Sie eine Funktion einsetzen können und was dabei beachtet werden muss. Daher soll in diesem Abschnitt einmal etwas Praktisches gemacht werden, womit einige C-typische Stärken aufgezeigt werden können. Es muss auch erwähnt werden, dass dieses Programmbeispiel Ihnen einiges an Wissen abverlangt. Im Listing werden aber keine Konstrukte von C verwendet, mit denen Sie bisher noch nichts zu tun hatten. Wenn Sie so wollen, stellt dieses Programm eine Art Zwischenprüfung Ihrer Kenntnisse in C dar.

Es soll gezeigt werden – wie Sie einen Text einer Datei dynamisch in den Speicher lesen können; wie dies bei Textverarbeitungsprogrammen geschieht. Eine einfache Textdatei ist dabei so strukturiert wie in Abbildung 16.11 gezeigt.

Abbildung 16.11 Einfache Strukturierung einer Textdatei

Sicher ist dies nur eine einfache Strukturierung einer Textdatei. In der Regel fehlen hierbei z. B. noch die Absätze oder die Seitenzahlen. Aber für unseren Fall genügt dies.

Folgende Funktionen benötigen Sie für diese Aufgabe:

  • eine Funktion, die eine Datei zum zeilenweisen Lesen öffnet
  • eine Funktion, die dynamischen Speicher für einen String anfordert
  • eine Funktion, die den dynamischen Speicher erweitert (eine Zeile hinzufügt)
  • eine Funktion, die die Größe einer Zeile anpasst und überflüssigen Speicher wieder freigibt
  • eine Funktion, die den dynamischen Speicher verringert
  • eine Funktion, die allozierten Speicher freigibt

Hier folgt jetzt das vollständige Listing, das sehr ausführlich kommentiert ist:

/* dyn_text.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* symbolische Konstanten */
#define LINE 255
#define ALLOC_LINE 10

enum { SUCCESS, ERROR };

/* Funktionsprototypen */
int read_file(char ***, char *, int *);
char **alloc_string_array(int, int);
int zeilen_hinzu_fuegen(char ***, int, int, int);
int string_anpassen(char **, int);
int string_groesse_veraendern(char **, int, int);
void free_string_array(char **, int);

/*  ***array == Ein Zeiger auf einen Zeiger einer Zeile mit
 *  einem Zeiger auf die Länge der Zeile (*array[zeile][länge])
 *  *fname == Name der zu öffnenden Datei
 *  *zeile_n == Zeiger auf Anzahl Zeilen
 *  Rückgabewert: SUCCESS wenn kein Fehler, ansonsten ERROR
 */
int read_file(char ***array, char *fname, int *zeile_n) {
 char puffer[LINE] = {0}; /* Puffer zum zeilenweisen Einlesen  */
 char *newline = NULL;    /* Zeiger für neue Zeile             */
 FILE *f;                 /* Datei, die geöffnet werden soll*/
 int error = SUCCESS;     /* Fehlerstatus                      */
 int zeile = 0;           /* aktuelle Zeile                    */
 int absatz_n;

 *zeile_n = 0;            /* erste Zeile mit 0 initialisieren  */
 /* Speicher anfordern für ALLOC_LINE Zeilen a LINE Zeichen    */
 *array = alloc_string_array(ALLOC_LINE, LINE);
 if(NULL != *array) {
    f = fopen(fname, "r"); /* Datei fname zum Lesen öffnen */
    if(NULL != f) {
       *zeile_n = ALLOC_LINE;
       absatz_n = 0;
       /* solange kein Fehler auftritt, zeilenweise einlesen */
       while(0 == error && NULL != fgets(puffer, LINE, f)) {
          newline = strchr(puffer, '\n');
          if(NULL != newline)
             /* Newline-Zeichen gegen
              * Terminierungszeichen austauschen */
               *newline = '\0';
             strcat( (*array)[zeile], puffer);
             if(NULL != newline) {
                absatz_n = 1;
                zeile++;
                /* Haben wir noch Platz im Speicher
                 * für weitere Zeilen? */
                if(zeile >= *zeile_n) {
                   /* Nein, dann anfügen. */
                   if(0 == zeilen_hinzu_fuegen(
                    array, *zeile_n, ALLOC_LINE, LINE) )
                      error = ERROR;
                   else
                      /* Anzahl der Zeilen + 10 */
                      *zeile_n += ALLOC_LINE;
                }
             }
             /* kein Newline-Zeichen, dann Zeile länger als LINE
              * Zeichen, String der Länge anpassen  ->  Speicher
              * anfordern */
             else {
                absatz_n++;
                if(0 == string_groesse_veraendern(
                 *array, zeile, absatz_n * LINE))
                   error = ERROR;
             }
       }/*while*/
       fclose(f);
       /* Wir sind am Ende vom Einlesen, oder ein Fehler trat auf.
        * Es muss/müssen allerdings noch die übrige(n) Zeile(n) in
        * den Speicher eingelesen werden. */
       if(0 == error && *zeile_n > zeile) {
          if(0 == zeilen_hinzu_fuegen(
           array, *zeile_n, zeile-*zeile_n, 0))
             error = ERROR;
          *zeile_n = zeile;
       }
    }
    else  /* Datei fname konnte nicht geöffnet werden. */
       error = ERROR;
 }
 else   /* Es konnte kein Speicher alloziert werden. */
     error = ERROR;

 if(error != 0) {
    /* im Fall eines Fehlers Speicher wieder freigeben
     * und Anzahl Zeilen auf 0 setzen */
    free_string_array(*array, *zeile_n);
    *zeile_n = 0;
 }
 else
     string_anpassen(*array, *zeile_n);
 return error;
}
/*   zeilen_n == Anzahl Zeilen, wie viele reserviert werden sollen
 *   laenge   == Speicherplatz für die Länge jeder Zeile,
 *               die angefordert wird
 *   Rückgabewert: Anfangsadresse des reservierten Speichers vom
 *                 String-Array  (array[zeile][laenge])
 */
char **alloc_string_array(int zeilen_n, int laenge) {
 char **array = NULL;
 int zeile;
 int ret = SUCCESS;

 if(zeilen_n > 0 && laenge > 0) {
    /* Speicher für zeilen_n Zeilen reservieren */
    array = malloc(zeilen_n * sizeof(*array));
    if(NULL != array) {
       for(zeile=0; zeile < zeilen_n; zeile++) {
          /* Für jede zeile_n Zeile laenge Bytes
           * Speicher reservieren */
          array[zeile] =
             malloc( laenge * sizeof(*array[zeile]) );
          if(NULL == array[zeile])
             ret = ERROR;
          else
             /*in jeder Zeile erstes Zeichen mit \0 initialisieren*/
             array[zeile][0] = '\0';
       }
       if(ERROR == ret) {  /* Bei Fehler Speicher freigeben */
          free_string_array(array, zeilen_n);
          array = NULL;
       }
    }
 }
 return array;
}

/*  ***array      == Ein Zeiger auf einen Zeiger einer Zeile mit
 * einem Zeiger auf die Länge der Zeile ( *array[zeile][länge])
 * alt_n_zeilen   == Anzahl akt. Zeilen im Speicher
 * n_zeilen_hinzu == Anzahl Zeilen, für die neuer Speicherplatz
 * reserviert werden soll. Bei negativen Werten werden n Zeilen
 * entfernt
 * init_laenge    == Speicherplatz für die Länge jeder Zeile, die
 *                   angefordert wird
 * Rückgabewert: 1 wenn Ok, ansonsten 0
 */
int zeilen_hinzu_fuegen(char ***array_ptr, int alt_n_zeilen,
                        int n_zeilen_hinzu, int init_laenge) {
 char **ptr;
 int ret = 1;
 int zeile;
 int anzahl_alte_zeilen = alt_n_zeilen;

 /* ein negativer Wert bedeutet Zeilen entfernen */
 if(n_zeilen_hinzu < 0) {
    for(zeile=anzahl_alte_zeilen-1;
     zeile >= anzahl_alte_zeilen+n_zeilen_hinzu; zeile--)
       free( (*array_ptr)[zeile]);
 }
 /* Speicher für einzelne Zeilen reservieren */
 ptr=realloc( *array_ptr,
  (anzahl_alte_zeilen+n_zeilen_hinzu)*sizeof(**array_ptr));
 if(NULL != ptr) {
    *array_ptr = ptr;
    for(zeile=anzahl_alte_zeilen;
     ret && zeile < anzahl_alte_zeilen+n_zeilen_hinzu; zeile++) {
       /* Anzahl der Zeichen, die jede Zeile
        * aufnehmen kann, reservieren */
       (*array_ptr)[zeile] = malloc(init_laenge);
       if( NULL != (*array_ptr)[zeile])
          /* in jeder Zeile das erste Zeichen mit \           * 0 initialisieren */
          (*array_ptr)[zeile][0] = '\0';
       else
          ret = 0;
    }
 }
 else
    ret = 0;
 return ret;
}

/*  **array_ptr == Ein Zeiger auf das String-Array
 *                 array[zeile][laenge]
 *      zeile_n == Anzahl Zeilen, die angepasst werden
 * Rückgabewert bei Erfolg 0, ansonsten größer als 0
 */
int string_anpassen(char **array_ptr, int zeile_n) {
 int zeile;
 int anzahl_zeichen;
 int fehlschlag = 0;

 for(zeile = 0; zeile < zeile_n; zeile++) {
    /* Funktion strlen liest das Terminierungszeichen
     * '\0' nicht mit -> daher +1 */
     anzahl_zeichen = strlen(array_ptr[zeile])+1;
     if(0 == string_groesse_veraendern(
      array_ptr, zeile, anzahl_zeichen))
        fehlschlag++;
 }
 return fehlschlag;
}

/*  **array_ptr == Ein Zeiger (Adresse) auf das String-Array
 *  array[zeile][laenge]
 *      zeile   == Zeile, die verändert werden soll
 * neu_laenge   == Anzahl Zeichen, die für die Zeile verändert
 *                 werden soll
 * Rückgabewert bei Erfolg SUCCESS, ansonsten bei Fehler ERROR
 */
int string_groesse_veraendern(char **array, int zeile,
                              int neu_laenge) {
 char *ptr;
 int ret = SUCCESS;

 ptr = realloc(array[zeile], neu_laenge);
 if(ptr != NULL)
   array[zeile] = ptr;
 else
   ret = ERROR;
 return ret;
}

/*  **array_ptr == Ein Zeiger (Adresse) auf das String-Array
 *                 array[zeile][laenge]
 *    n_zeile   == Anzahl Zeilen, die freigegeben werden sollen*/
void free_string_array(char **array, int n_zeilen) {
 int zeile;

 if(array != NULL) {
    for(zeile= 0; zeile < n_zeilen; zeile++) {
       if(array[zeile] != NULL)
          free(array[zeile]);
    }
 }

 free(array);
}

int main(void) {
 char **array = NULL;
 char datei[255];
 int zeilen=0, i, auswahl, n, m;

 do {
    printf("Was wollen Sie tun?\n\n");
    printf("-1- Datei komplett in den Speicher einlesen\n");
    printf("-2- Inhalt der Datei im Speicher ausgeben\n");
    printf("-3- Datei im Speicher von Zeile n bis m ausgeben\n");
    printf("-4- Den Speicher wieder freigeben\n");
    printf("-5- Ende\n\n");
    printf("Ihre Wahl : < >\b\b");
    scanf("%d",&auswahl);fflush(stdin);
    switch(auswahl) {
       case 1 : printf("Datei angeben( mit Pfadangabe ): ");
                scanf("%254s",datei);
                fflush(stdin);
                if( (read_file(&array, datei, &zeilen))==ERROR)
                    printf("Fehler beim Lesen in Speicher!!!\n");
                break;
       case 2 : if(zeilen == 0)
                   printf("Keine Daten vorhanden!\n");
                else
                   for(i=0; i<=zeilen-1; i++)
                      printf("%s\n",array[i]);
                break;
       case 3 : printf("Zeilenbeginn: ");
                scanf("%d",&n);
                fflush(stdin);
                if(n > 0 && n <= zeilen-1) {
                   printf("bis zur Zeile: ");
                   scanf("%d",&m);
                   fflush(stdin);
                   if(m >= n && m <= zeilen-1) {
                      for(i=n; i<=m-1; i++)
                         printf("%s\n",array[i]);
                   }
                   else
                      printf("??>>%d<<??\n",m);
                }

                else
                   printf("??>>%d<<??\n",n);
                break;
       case 4 : free_string_array(array, zeilen);
                zeilen=0;
                break;
       default: break;
    }
 } while(auswahl != 5);
 return EXIT_SUCCESS;
}


Ihr Kommentar

Wie hat Ihnen das <openbook> gefallen? Wir freuen uns immer über Ihre freundlichen und kritischen Rückmeldungen. >> Zum Feedback-Formular
<< zurück
  
  Zum Katalog
Zum Katalog: C von A bis Z

 C von A bis Z
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das <openbook> gefallen?
Ihre Meinung

 Buchtipps
Zum Katalog: C/C++






 C/C++


Zum Katalog: Einstieg in C






 Einstieg in C


Zum Katalog: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Katalog: C++ Handbuch






 C++ Handbuch


Zum Katalog: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


 Shopping
Versandkostenfrei bestellen in Deutschland und Österreich
InfoInfo




Copyright © Rheinwerk Verlag GmbH 2009
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.


[Rheinwerk Computing]

Rheinwerk Verlag GmbH, Rheinwerkallee 4, 53227 Bonn, Tel.: 0228.42150.0, Fax 0228.42150.77, service@rheinwerk-verlag.de