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

Jetzt 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.16 Zeilenweise Ein-/Ausgabe von Streams Zur nächsten ÜberschriftZur vorigen Überschrift


Rheinwerk Computing - Zum Seitenanfang

16.16.1 Zeilenweise lesen mit »gets()«/»fgets()« Zur nächsten ÜberschriftZur vorigen Überschrift

Nun folgen die Funktionen zum zeilenweisen Lesen und Schreiben von einem oder in einen Stream. Betrachten wir zuerst die Funktionen zum zeilenweisen Lesen:

#include <stdio.h>

char *gets(char *puffer);
char *fgets(char *puffer, int n, FILE *datei);
wchar_t *fgetws( wchar_t *puffer, int n, FILE *datei);

Mit fgets() (und der Version für breite Zeichen, fgetws()) werden zeilenweise n – 1 Zeichen vom Eingabe-Stream datei bis zum nächsten Newline-Zeichen gelesen. Die gelesene Zeile befindet sich in der Adresse von puffer mit dem Newline-Zeichen '\n' (bzw. L'\n') und dem abschließenden '\0'-Zeichen (bzw. L'\0'). Mit gets() können Sie ebenso zeilenweise einlesen, allerdings nur von der Standardeingabe (stdin) und mit dem Unterschied, dass bei gets() das Newline-Zeichen durch das '\0'-Zeichen ersetzt wird. Alle drei Versionen liefern bei Erfolg das Argument puffer oder bei einem Fehler einen NULL-Zeiger zurück. Auch ein NULL-Zeiger wird zurückgeliefert, wenn das Dateiende erreicht wurde, ohne dass ein Zeichen gelesen wurde.

gets() ist eine unsichere Funktion, weshalb es hierfür keine Version für breite Zeichen gibt. Ein Beispiel für die Verwendung von gets() wäre:

/* gets.c */
#include <stdio.h>
#include <stdlib.h>

int main(void) {
   char name[20];

   printf("Bitte geben Sie Ihren Namen ein : ");
   gets(name);  /* Gefährlich */
   printf("Hallo %s\n",name);
   return EXIT_SUCCESS;
}

Unter Linux/UNIX wird der Compiler bei diesem Programm vernünftigerweise eine Warnung ausgeben. Die Warnung, diese Funktion nicht zu verwenden, ist in Ordnung, aber vielleicht sollte ich gerade für Anfänger auch noch den Grund und die Alternativen bei der Fehlermeldung mit angeben.

Da die Funktion gets() nicht die Anzahl der einzugebenden Zeichen überprüft, kann dies zu einem Pufferüberlauf (Buffer-Overflow) führen. Deshalb sollten Sie auf keinen Fall gets(), sondern die Funktion fgets() verwenden.

Wenn Sie die Syntax von fgets() betrachten, bemerken Sie, dass sich darin außer der Zieladresse, in der die Daten eingelesen werden, zusätzlich ein Stream (FILE Zeiger) und ein Integer-Wert befinden, der die Anzahl der einzulesenden Zeichen festlegt. Mit fgets werden somit n Zeichen oder wird bis zum nächsten Newline ('\n') aus dem Stream in die Adresse von puffer gelesen, wobei der Stream eine beliebig geöffnete Datei oder auch die Standardeingabe (stdin) sein kann. Hierzu sehen Sie das vorige Beispiel mit fgets():

/* fgets1.c */
#include <stdio.h>
#include <stdlib.h>
#define MAX 20

int main(void) {
   char name[MAX];
   printf("Bitte geben Sie Ihren Namen ein : ");
   fgets(name, MAX, stdin);
   printf("Hallo %s",name);
   return EXIT_SUCCESS;
}

Sollten hier mehr als 20 Zeichen eingegeben werden, läuft das Programm trotzdem für immer anstandslos. Es werden 20 Zeichen bzw. 18 darstellbare Zeichen + '\n' + '\0' an den String name übergeben. Ein Vorteil ist, dass mit fgets() nicht nur von stdin gelesen werden kann, sondern auch von einem beliebigen Stream. Hier folgt ein Beispiel, wie Sie mit fgets() zeilenweise aus einer Datei lesen können:

/* fgets2.c */
#include <stdio.h>
#include <stdlib.h>
#define ZEILENLAENGE 80

int main(void) {
   FILE *quelle;
   char puffer[ZEILENLAENGE], name[20];

   printf("Welche Datei wollen Sie zum Lesen öffnen: ");
   scanf("%s",name);
   if( (quelle=fopen(name,"r")) == NULL) {
      fprintf(stderr, "Kann %s nicht oeffnen\n", name);
      return EXIT_FAILURE;
   }
   while(fgets(puffer, ZEILENLAENGE, quelle))
      fputs(puffer, stdout);
   return EXIT_SUCCESS;
}

Weil beim Einlesen vom Stream der Standardeingabe (stdin) mit fgets() auch das '\n'-Zeichen mit eingelesen wird, verwenden einige Programmierer – sei es aus Faulheit oder mangelndem Wissen – die Funktion gets(), obwohl sie wissen, dass sie diese Funktion nicht verwenden sollten. Häufig haben diese Programmierer Probleme mit dem Newline-Zeichen am Ende von Stringvergleichen, wie das folgende Beispiel zeigt:

/* fgets3.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PASSWORT "Schiller"
#define MAX 10

int main(void) {
   char pswd[MAX];

   printf("Passwort: ");
   fgets(pswd, MAX, stdin);
   if(strcmp(PASSWORT, pswd) == 0)
      printf("Willkommen\n");
   else
      printf("Passwort falsch\n");
   return EXIT_SUCCESS;
}

Auch wenn hier der Benutzer das richtige Passwort eingibt, schlägt der Stringvergleich fehl, weil fgets() das Newline-Zeichen mit einliest. Dieses Problem lässt sich mit ein paar Zeilen Code beheben:

/* fgets4.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define PASSWORT "Schiller"
#define MAX 10

void chomp(char *str) {
   size_t p=strlen(str);
   /* '\n' mit '\0' überschreiben */
   str[p-1]='\0';
}

int main(void) {
   char pswd[MAX];

   printf("Passwort: ");
   fgets(pswd, MAX, stdin);
   /* ... letztes Zeichen vor \0 entfernen */
   chomp(pswd);

   if(strcmp(PASSWORT, pswd) == 0)
      printf("Willkommen\n");
   else
      printf("Passwort falsch\n");
   return EXIT_SUCCESS;
}

Die Funktion chomp() tut nichts anderes, als das letzte Zeichen vor dem Terminierungszeichen '\0' zu entfernen. Dabei wird die Anzahl der Zeichen mit der Funktion strlen() gezählt. Zieht man von diesem Wert eins ab und verwendet ihn als Indexzähler mit dem Indizierungsoperator, befinden Sie sich ein Zeichen vor '\0'.


Rheinwerk Computing - Zum Seitenanfang

16.16.2 Zeilenweise schreiben mit »puts()«/»fputs()« Zur nächsten ÜberschriftZur vorigen Überschrift

Hier sehen Sie die Syntax der drei schreibenden Gegenstücke zu gets(), fgets() und fgetws():

#include <stdio.h>

int puts(const char *puffer);
int fputs(const char *puffer, FILE *datei);
int fputws(const wchar_t *puffer, FILE *datei);

Mit puts() wird der null-terminierte String puffer auf dem Bildschirm (stdout) ausgegeben. Außerdem gibt puts() am Ende der Zeichenkette noch ein Newline-Zeichen mit aus, was die Funktion fputs() (bzw. fputws()) hingegen nicht macht. Im Gegensatz zu puts(), mit dem Sie nur auf die Standardausgabe (stdout) schreiben können, verwendet fputs() (bzw. die Version für breite Zeichen, fputws()), den geöffneten Ausgabe-Stream datei, in den geschrieben wird. Als Ausgabe-Stream ist eine Datei zulässig, die im Schreibmodus geöffnet wurde, oder auch die Standardausgabe (stdout). Das abschließende Null-Zeichen wird von fputs() und fputws() nicht in den Ausgabe-Stream geschrieben. Der Rückgabewert von allen drei Funktionen ist im Falle eines Fehlers EOF (bzw. WEOF) oder bei Erfolg eine nicht-negative Ganzzahl.

/* fputs.c */
#include <stdio.h>
#include <stdlib.h>
#define ZEILENLAENGE 80

int main(void) {
   FILE *quelle, *kopie;
   char puffer[ZEILENLAENGE], name[20];

   printf("Welche Datei wollen Sie zum Lesen öffnen: ");
   scanf("%s",name);

   if( (quelle=fopen(name,"r")) == NULL) {
      fprintf(stderr,"Kann %s nicht oeffnen\n",name);
      return EXIT_FAILURE;
   }
   if( (kopie=fopen("kopie.txt","w")) == NULL) {
      fprintf(stderr,"Kann kopie.txt nicht oeffnen\n");
      return EXIT_FAILURE;
   }
   while(fgets(puffer,ZEILENLAENGE,quelle)) {
      fputs(puffer, kopie);
      puts(puffer);
   }
   return EXIT_SUCCESS;
}

fputs() wird hier eingesetzt, um den Puffer, der mit fgets() ausgelesen wurde, in eine Datei namens kopie.txt zu schreiben. puts() hingegen gibt alles auf dem Bildschirm aus. Somit wird eine Zeile in die Datei kopie.txt geschrieben und dasselbe gleich nochmals auf dem Bildschirm ausgegeben.


Rheinwerk Computing - Zum Seitenanfang

16.16.3 Zeilenweise vom Stream einlesen mit »getline()« (nicht ANSI C) Zur nächsten ÜberschriftZur vorigen Überschrift

Den Benutzern des GNU-GCC-Compilers sei noch die Funktion getline() ans Herz gelegt. Sie gehört zwar nicht zum Umfang von ANSI C, jedoch wird in The GNU C Library Reference Manual unter www.gnu.org explizit darauf verwiesen. Warum diese Funktion so besonders ist, wird im Anschluss erläutert.

Die Funktion getline() kann als Ersatz für die E/A-Funktion fgets() verwendet werden oder noch allgemeiner – für das Einlesen einer Zeile von einem Stream. Zunächst aber sehen wir uns die Syntax der Funktion an, die in <stdio.h> deklariert ist:

ssize_t getline (char **lineptr, size_t *n, FILE *stream)

Die Funktion liest eine Zeile inklusive dem Newline ('\n') und dem Stringende-Zeichen ('\0') in einen Puffer ein und speichert die Adresse des Puffers in *lineptr.

Bevor Sie getline() aufrufen, sollten Sie in *lineptr die Adresse eines zuvor mit malloc() allozierten Puffers der Länge *n Bytes bereitstellen.

Jetzt kommt der eigentliche Clou an der Sache: Ist der übergebene Puffer groß genug, erhalten Sie in etwa den Zustand, den Sie auch mit der Funktion fgets() erreichen können. Ist dies aber nicht der Fall, verhält sich getline() nicht wie fgets() und hört bei Überschreitung der angegebenen Puffergröße einfach auf, die Zeile einzulesen. Vielmehr wird der Puffer innerhalb der Funktion auf die erforderliche Größe mit realloc() angepasst. Wenn Sie sich dieses Szenario nun noch mit der Funktion gets() vorstellen, ist das eigenständige Kürzen der einzulesenden Zeile, wie es bei fgets() geschehen würde, noch das geringere Übel.

Das war aber noch nicht alles. Wird *lineptr vor dem Aufruf mit einem NULL-Zeiger initialisiert und *n auf 0 gesetzt, übernimmt getline() die Bereitstellung des Speichers für die Zeile vollkommen selbstständig, und Sie müssen sich um nichts weiter kümmern.

Die Funktion gibt die Anzahl der eingelesenen Zeichen inklusive des Zeilentrennzeichens ('\n'), aber ohne das abschließende Terminierungszeichen ('\0') zurück – bei einem Fehler oder bei EOF erhalten Sie von getline() –1.

Wenn Sie getline() verwenden wollen, müssen Sie die Konstante _GNU_SOURCE vor allen include-Anweisungen definieren. Laut der GNU-Dokumentation ist diese Funktion der empfohlene Weg, Zeilen vom Stream zu lesen. Sie gilt als die sicherste ihrer Art. In diesem Zusammenhang sei aber nochmals auf The GNU C Library Reference Manual verwiesen.

Hier sehen Sie ein einfaches Beispiel für den Fall, dass Sie die Bereitstellung des Puffers vollständig getline() überlassen wollen:

/* getline.c */
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>

int main(void) {
   FILE *fd;
   /* bitte die Datei und eventuell den Pfad anpassen */
   char *datei = "/home/user/testdatei.txt";
   int nRet;
   size_t *t = malloc(0);

   char **gptr = malloc(sizeof(char*));
   *gptr = NULL;

   if ( (fd = fopen(datei,"r")) == NULL) {
      fprintf(stderr, "\nKonnte Datei %s nicht öffnen!", datei);
      return EXIT_FAILURE;
   }
   while( (nRet=getline(gptr, t, fd)) > 0)
      fputs(*gptr,stdout);
  return EXIT_SUCCESS;
}

Rheinwerk Computing - Zum Seitenanfang

16.16.4 Rezepte für zeilenweises Einlesen und Ausgeben topZur vorigen Überschrift

Es folgen jetzt einige nützliche Listings, die häufig zum zeilenweisen Einlesen und Ausgeben benötigt werden. Es sind Beispiele, die sich mit Problemen wie den folgenden befassen:

  • Wie kann ich die n-te Zeile auslesen?
  • Wie kann ich von Zeile n1 bis n2 lesen?
  • Wie kann ich alle Zeilen ausgeben, die eine bestimmte Stringfolge enthalten?
  • Wie kann ich alle Zeilen ausgeben, die ein bestimmtes Wort enthalten?
  • Suchen und Ersetzen in einer Textdatei (nur ganze Wörter, keine Teilstrings)

Wie kann ich die n-te Zeile auslesen?

/* read_nline.c */
#include <stdio.h>
#include <stdlib.h>
#define BUF 255

char temp[BUF];
char puffer[BUF];

/* Auslesen der n-ten Zeile */
char *getsline_number(int n, FILE *file) {
   int i;

   for(i = 0; i < n-1; i++)
      if(fgets(temp, BUF, file) == NULL)
         /* Bis zur n-ten Zeile lesen */
         return NULL; /* Zeile scheint nicht zu existieren. */
   /* Stream ist jetzt in der n-ten Zeile. */
   if(fgets(puffer,BUF,file) == NULL)
      return NULL; /* Zeile scheint nicht zu existieren. */
   return puffer; /* Zeile an Aufrufer zurückgeben */
}

int main(int argc, char *argv[]) {
   FILE *f;
   unsigned int line;
   char *linenr;

   if(argc < 2) {
      fprintf(stderr, "Verwendung : %s datei\n",*argv);
      return EXIT_FAILURE;
   }
   f = fopen(argv[1],"r");
   if(f == NULL) {
      printf("Fehler beim Öffnen");
      return EXIT_FAILURE;
   }
   printf("Welche Zeile wollen Sie lesen : ");
   scanf("%d",&line);

   linenr=getsline_number(line, f);
   if(linenr == NULL) {
      fprintf(stderr, "Fehler beim Lesen der"
                      " %d-ten Zeile??\n",line);
      return EXIT_FAILURE;
    }
   printf("Zeile %d : %s\n", line, linenr);
   return EXIT_SUCCESS;
}

Wie kann ich von Zeile n1 bis n2 lesen?

/* read_line_n2n.c */
#include <stdio.h>
#include <stdlib.h>
#define BUF 255
char temp[BUF];
char puffer[BUF];
int i;  /* Zeilenzähler */

/* Lesen von Zeile n1 bis Zeile n2 */
char *getsline_number(int n1,int n2, FILE *file) {
   for(i = 0; i < n1-1; i++)
      /* Bis zur n1-ten Zeile lesen */
      if(fgets(temp, BUF, file) == NULL)
         return NULL; /* Zeile scheint nicht zu existieren. */
   /* Jetzt beginnt das eigentliche Lesen. */
   printf("\n\n");
   for(i = n1; i <= n2; i++) {
      if(fgets(puffer,BUF,file) == NULL)
         /* Stream ist jetzt in der n-ten Zeile. */
         return NULL;  /* Zeile scheint nicht zu existieren. */
      printf("Zeile %d : %s", i, puffer);
   }
}

int main(int argc, char *argv[]) {
   FILE *f;
   int line1, line2;
   char *linenr;

   if(argc < 2) {
      fprintf(stderr, "Verwendung : %s datei\n", *argv);
      return EXIT_FAILURE;
   }
   f = fopen(argv[1],"r");
   if(f == NULL) {
      printf("Fehler bei fopen()...\n");
      return EXIT_FAILURE;
   }
   printf("von Zeile wollen Sie lesen : ");
   scanf("%d", &line1);
   printf("bis Zeile wollen Sie lesen : ");
   scanf("%d", &line2);


   if(line2 < line1) {
      fprintf(stderr, "bis-Zeile kann nicht "
                      "groesser sein als von-Zeile!\n");
      return EXIT_FAILURE;
   }
   linenr=getsline_number(line1,line2, f);
   if(linenr == NULL) {
      fprintf(stderr, "Fehler beim Lesen "
                      "der %d-ten Zeile??\n",i);
      return EXIT_FAILURE;
   }
   printf("\n");
   return EXIT_SUCCESS;
}

Wie kann ich alle Zeilen ausgeben, die eine bestimmte Stringfolge enthalten?

/* search_string.c */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define BUF 255

int main(int argc, char *argv[]) {
   FILE *f;
   char searchstring[BUF], puffer[BUF];
   int counter = 1;

   if(argc < 2) {
      fprintf(stderr, "Verwendung : %s datei\n", *argv);
      return EXIT_FAILURE;
   }
   f = fopen(argv[1], "r");
   if(f == NULL) {
      printf("Fehler bei fopen()... \n");
      return EXIT_FAILURE;
   }
   printf("Wonach suchen Sie in %s : ", argv[1]);
   scanf("%s", searchstring);
   printf("\n");
   while( fgets(puffer, BUF, f) != NULL ) {
      if(strstr(puffer,searchstring) != 0)
         printf("Zeile %d : %s",counter,puffer);
      counter++;
   }
   printf("\n");
   return EXIT_SUCCESS;
}

Der Nachteil an diesem Beispiel ist, dass strstr() praktisch alle Stringfolgen ausgibt. Suchen Sie beispielsweise nach der Stringfolge »int«, dann gibt strstr() auch »wahr« aus, wenn die Folge »printf«, »fprintf«, »Lint«, »Mint« … lautet. Wenn dies so gewollt ist, dann ist es in Ordnung. Falls nicht, muss mit strtok() ein Worttrenner eingebaut werden.

Wie kann ich alle Zeilen ausgeben, die ein bestimmtes Wort enthalten?

/* search_word.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUF 255

/* Anpassen nach Bedarf... */
const char trennzeichen[] = ".;,:\"\' ";

int main(int argc, char *argv[]) {
   FILE *f;
   char searchstring[BUF];
   char puffer[BUF], puffer_bak[BUF];
   int counter=1;
   char *wort;

   if(argc < 2) {
      fprintf(stderr, "Verwendung : %s datei\n",*argv);
      return EXIT_FAILURE;
      }
   f=fopen(argv[1],"r");
   if(f == NULL) {

      printf("Fehler bei fopen()...");
      return EXIT_FAILURE;
   }
   printf("Wonach suchen Sie in %s : ",argv[1]);
   scanf("%s", searchstring);
   printf("\n");

   while(fgets(puffer, BUF, f) != NULL) {
      strcpy(puffer_bak, puffer);
      wort = strtok(puffer, trennzeichen);
      while(wort != NULL) {
         if(strcmp(wort,searchstring) == 0)
            printf("Zeile %d : %s",counter,puffer_bak);
         wort = strtok(NULL,trennzeichen);
      }
      counter++;
   }
   printf("\n");
   return EXIT_SUCCESS;
}

Suchen und Ersetzen in einer Textdatei (nur ganze Wörter, keine Teilstrings)

/* search_and_replace.c */
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#define STRING_MAX 8192

int wort_begrenzer(char c) {
   return (c == ' ' || c == '\n' || c == '\t' || c == '\0' ||
       c == '.' || c == ',' || c == ';' || c == '!' ||c == '?');
}

/* Newline von fgets() entfernen */
void chomp(char *str) {
 size_t p=strlen(str);
 str[p-1] = '\0';
}
int main(int argc, char *argv[]) {
   FILE *file, *copy;
   char alt_string[STRING_MAX+1],neu_string[STRING_MAX+1],
        such_wort[STRING_MAX+1],replace_wort[STRING_MAX+1],
        *zgr;
   char puffer[STRING_MAX+1];
   int such_wortlen, i=0,w;
   size_t len=0;

   if(argc < 2) {
      fprintf(stderr, "Verwendung: %s datei\n", *argv);
      return EXIT_FAILURE;
   }
   file = fopen(argv[1],"r");   /* Datei zum Lesen öffnen     */
   copy = fopen(argv[1],"r+");  /* Datei zum Schreiben öffnen */
   if(file == NULL || copy == NULL) {
      printf("Fehler bei fopen()...\n");
      return EXIT_FAILURE;
   }
   alt_string[0]='\0';
   /* kompletten String in alt_string legen ... */
   /* Bitte ggf. selbst durch dynamische Speicherverwaltung
     * genügend Platz schaffen! */
   while( (fgets(puffer,STRING_MAX+1,file)) != NULL ) {
      len += strlen(puffer)+1;
      if(len < STRING_MAX)
         strcat(alt_string, puffer);
      else {
         printf("Puffergroesse ueberschritten!\n");
         break;
      }
   }
   neu_string[0]='\0';

   printf("Welches Wort wollen Sie ersetzen : ");
   fgets(such_wort, STRING_MAX, stdin );
   chomp(such_wort);

   such_wortlen = strlen(such_wort); /* Länge des Suchwortes */

   for(w = 0; w < such_wortlen; w++)
   /* nach Wortbegrenzern duchlaufen ... */
   if(wort_begrenzer(such_wort[w])) {
      printf("Keine Wortbegrenzer im Suchwort!!!\n");
      return EXIT_FAILURE;
   }
   printf("Durch welches Wort wollen Sie ersetzen : ");
   fgets(replace_wort, STRING_MAX, stdin);
   chomp(replace_wort);
   i = 0;
   while(1){
      if( (zgr=strstr(&alt_string[i], such_wort)) == NULL) {
         /* Kein Wort zu ersetzen */
         strcat(neu_string, &alt_string[i]);
         break;
      }
      else { /*..ansonsten von Byte i bis zgr in neu_string*/
         strncat(neu_string, &alt_string[i], zgr-&alt_string[i]);
         /* jetzt überprüfen, ob wir ein Wort haben und
          * keinen Teilstring oder ob das Wort am Anfang steht */
         if( (zgr-&alt_string[0]==0 ||
              wort_begrenzer( *(zgr-1))) &&
              wort_begrenzer( *(zgr+such_wortlen))) {
            strcat(neu_string, replace_wort);
            /* Nach ersetztem Wort den Zeiger setzen ... */
            i += zgr + such_wortlen-&alt_string[i];
         }
         else {
            strncat(neu_string, zgr, 1);
            i += zgr + 1-&alt_string[i];
         }
      }
   } /* Ende while(1) */
   /* Für Testausgabe ... */
   /* printf("Neuer String : %s\n",neu_string); */
   strcpy(alt_string, neu_string);
   /* Achtung jetzt wirds ernst,
    * für Testausgabe in Kommentar setzen. */
   fputs(alt_string, copy);
   neu_string[0] = '\0';
   return EXIT_SUCCESS;
}


Ihre Meinung

Wie hat Ihnen das Openbook gefallen? Wir freuen uns immer über Ihre Rückmeldung. Schreiben Sie uns gerne Ihr Feedback als E-Mail an kommunikation@rheinwerk-verlag.de.

<< zurück
  
  Zum Rheinwerk-Shop
Zum Rheinwerk-Shop: C von A bis Z

 C von A bis Z
Jetzt bestellen


 Ihre Meinung?
Wie hat Ihnen das Openbook gefallen?
Ihre Meinung

 Buchtipps
Zum Rheinwerk-Shop: C/C++






 C/C++


Zum Rheinwerk-Shop: Einstieg in C






 Einstieg in C


Zum Rheinwerk-Shop: Schrödinger programmiert C++






 Schrödinger
 programmiert C++


Zum Rheinwerk-Shop: C++ Handbuch






 C++ Handbuch


Zum Rheinwerk-Shop: IT-Handbuch für Fachinformatiker






 IT-Handbuch für
 Fachinformatiker


 Lieferung
Versandkostenfrei bestellen in Deutschland, Österreich und der Schweiz
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.


Nutzungsbestimmungen | Datenschutz | Impressum

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

Cookie-Einstellungen ändern