problem mit strings aus textdatei in feld kopieren... brauch dringend hilfe!



  • ich soll ein programm schreiben, das eine textdatei einliest und statistisch auswertet.

    hier mal der teil der aufgabe, bei dem ich nich weiter weiß:

    3. Einlesen der Textdatei und Abspeicherung der einzelnen Textzeilen der Datei.
    • Die Verwaltung der eingelesenen Zeilen erfolgt über ein Feld mit 'Zeiger auf char'-Elementen.
    • Die eigentlichen Stringvariablen (char-Felder) für die einzelnen Zeilen sind zur Laufzeit des
    Programms mit malloc oder calloc dynamisch zu erzeugen. Diese dynamischen Strings dürfen
    nur die für die jeweilige Zeile benötigte Größe strlen(..)+1 haben.
    • Das Lesen von jeweils einer Zeile aus der Textdatei erfolgt mit dem gelieferten
    Unterprogramm GetFileLine, das sich in der Programm-Bibliothek fileread.h/cpp
    befindet.
    char* GetFileLine( char* PtrFileName, char*PtrTextBuf, int TextBufSize );
    Die Funktion liefert bei jedem Aufruf eine Zeile der Textdatei. Als Rückgabewert wird ein
    Zeiger auf das erste Zeichen der Textzeile, bzw. bei Öffnungsfehler oder Dateiende die
    Konstante NULL geliefert.
    Die genaue Vorgehensweise kann der Datei fileread.h entnommen werden.
    ----

    erste versuche ergaben folgendes:

    #include
    #include
    #include

    int main (void)
    {
    char zeile;
    zeile = (char
    ) calloc (25, sizeof(char));
    do {
    getFileLine("testtext", zeile, 100);
    puts(zeile);
    printf("\n%c\n", zeile[0]);
    } while (zeile != NULL);
    getchar();
    free (zeile);
    return 0;
    }

    -----

    irgendwie haut das alles gar nicht hin. ich hab kein plan.



  • Probleme unter anderem:

    Du allokierst 25 chars, liest aber aus der Datei 100 Zeichen.
    Du benutzt nicht den Rückgabewert von der vorgegebenen Funktion.

    Und ohne Angabe von fileread.h/cpp kann man eh nicht großartig weiterhelfen.

    Ausserdem gibt es spezielle C/C++ Tags für den Code.



  • hier mal die beiden dateien fileread.h und fileread.cpp:

    //****************************************************************************
    // >fileread.h  :   Deklaration    Liefere bei jedem Aufruf
    //  fileread.cpp:   Definition     eine Zeile einer Textdatei
    //============================================================================
    // Projekt: universelles Modul (Bibliothek)
    // Autor  : 
    // Version: 2.0
    //          1.0  07.12.2000  Urversion
    //          2.0  19.02.2005  neu: Aufrufmodus offene Datei schliessen,
    //                           Umstrukturierung des Moduls auf State-Machine
    //
    // Beschreibung: siehe unten
    // Compiler    : Borland C++ V 5.01
    //****************************************************************************
    
    //****************************************************************************
    // getFileLine() : eine Dateizeile einer Texdatei lesen und zurueckliefern
    //****************************************************************************
    // Eingang:
    // ========
    // ptrFileName  Zeiger auf den Dateinamen der zu lesenden Textdatei.
    // ptrTextBuf   Zeiger auf char-Feld mit mindestens TextBufSize Elementen.
    //              - Es werden alle Zeichen einer Dateizeile maximal jedoch
    //                TextBufSize-1 Zeichen einer Dateizeile gelesen.
    //              - Das Zeilenende-Zeichen '\n' wird nicht in den Zielstring
    //                uebernommen.
    //              - Wenn die Dateizeile laenger als TextBufSize-1 Zeichen ist,
    //                gehen die restlichen Zeichen der Dateizeile verloren.
    // textBufSize  Groesse des char-Feldes (maximale Zeichenzahl+'\0').
    //
    // Ein Lesevorgang kann jederzeit beendet werden, indem die Funktion beim
    // Auruf in einem der beiden Zeiger den Wert NULL erhaelt. Eine offene Datei
    // wird in diesem Fall geschlossen.
    // Die Puffergroesse muss groesser 2 sein, es wird also immer mindestens
    // 1 Zeichen einer Dateizeile gelesen.
    //
    // Ausgang:
    // ========
    // return       Zeigerkonstante NULL bei Datei-Oeffnungsfehler oder Dateiende
    // Wert         alles ok: Adresse des 1. gelesenen Zeichens (&PtrTextBuf[0])
    //****************************************************************************
    
    #ifndef FILEREAD_H           // ggf. Makroname definieren, damit die Datei bei
      #define FILEREAD_H         // mehrfach-includes nur einmal eingefuegt wird
    
      char* getFileLine( char* ptrFileName, char* ptrTextBuf, int textBufSize );
    
    #endif                                      // Ende der bedingten Compilierung
    
    // Ende Datei fileread.h
    

    -------------------------------------------

    //****************************************************************************
    //  fileread.h  :   Deklaration    Liefere bei jedem Aufruf
    // >fileread.cpp:   Definition     eine Zeile einer Textdatei
    //============================================================================
    // Projekt: universelles Modul (Bibliothek)
    // Autor  : 
    // Version: 2.0
    //          1.0  07.12.2000  Urversion
    //          2.0  19.02.2005  neu: Aufrufmodus offene Datei schliessen,
    //                           Umstrukturierung des Moduls auf State-Machine
    //
    // Beschreibung: siehe unten
    // Compiler    : Borland C++ V 5.01
    //****************************************************************************
    
    //****************************************************************************
    // getFileLine() : eine Dateizeile einer Texdatei lesen und zurueckliefern
    //****************************************************************************
    // Eingang:
    // ========
    // ptrFileName  Zeiger auf den Dateinamen der zu lesenden Textdatei.
    // ptrTextBuf   Zeiger auf char-Feld mit mindestens TextBufSize Elementen.
    //              - Es werden alle Zeichen einer Dateizeile maximal jedoch
    //                TextBufSize-1 Zeichen einer Dateizeile gelesen.
    //              - Das Zeilenende-Zeichen '\n' wird nicht in den Zielstring
    //                uebernommen.
    //              - Wenn die Dateizeile laenger als TextBufSize-1 Zeichen ist,
    //                gehen die restlichen Zeichen der Dateizeile verloren.
    // textBufSize  Groesse des char-Feldes (maximale Zeichenzahl+'\0').
    //
    // Ein Lesevorgang kann jederzeit beendet werden, indem die Funktion beim
    // Auruf in einem der beiden Zeiger den Wert NULL erhaelt. Eine offene Datei
    // wird in diesem Fall geschlossen.
    // Die Puffergroesse muss groesser 2 sein, es wird also immer mindestens
    // 1 Zeichen einer Dateizeile gelesen.
    //
    // Ausgang:
    // ========
    // return       Zeigerkonstante NULL bei Datei-Oeffnungsfehler oder Dateiende
    // Wert         alles ok: Adresse des 1. gelesenen Zeichens (&PtrTextBuf[0])
    //****************************************************************************
    
    #include "fileread.h"  // eigene Headerdatei einfuegen
    #include <stdio.h>     // C-I/O-Bibliothek   : FILE, fopen(), flose(), fgets()
    #include <string.h>    // C-String-Bibliothek: strlen()
    
    // Vereinbarung von Konstanten zur Steuerung des Lesevorgangs
    //****************************************************************************
    enum { FS_FILE_IS_CLOSED, FS_FILE_IS_OPEN };                 // Datei  -Status
    enum { AS_IDLE, AS_OPEN_FILE, AS_CLOSE_FILE, AS_GET_LINE };  // Aktions-Status
    //****************************************************************************
    
    char* getFileLine( char* ptrFileName, char* ptrTextBuf, int textBufSize ) {
    
      static int   fileStatus    = FS_FILE_IS_CLOSED;               // File-Status
      static int   actionStatus  = AS_IDLE;            // Aktions-Status: Ruhelage
      static FILE* fp            = NULL;                            // Dateizeiger
      auto   char* ptrReturn     = NULL;                       // Rueckgabe-Zeiger
      auto   int   iLastChar;                 // Index letztes Zeichen einer Zeile
      auto   int   c;               // ueberzaehlige Zeichen einer Zeile entfernen
    
      // State-Machine: durchzufuehrende Aktion bestimmen
      if( ptrFileName == NULL || ptrTextBuf == NULL || textBufSize < 2 )
          actionStatus = AS_CLOSE_FILE;            // Nutzer will Datei schliessen
        else if( fileStatus == FS_FILE_IS_OPEN )
          actionStatus = AS_GET_LINE;      // normaler Betrieb: Dateizeile liefern
        else if( fileStatus == FS_FILE_IS_CLOSED )
          actionStatus = AS_OPEN_FILE;   // neue Datei: Beginn eines Lesezyklusses
        else
          actionStatus = AS_IDLE;                        // Ruhelage: keine Aktion
    
      // State-Machine: Aktionen ausfuehren
      // Achtung: bedingte u. unbedingte implizite Zweiguebergaenge
      //          Die case-Reihenfolge darf nicht veraendert werden.
      switch( actionStatus ) {
        case AS_OPEN_FILE:
          fp = fopen( ptrFileName, "rt" );         // Textdatei fuer Lesen oeffnen
          if( fp != NULL )    // Oeffnung erfolgreich: weiter mit case AS_GET_LINE
             { fileStatus = FS_FILE_IS_OPEN;  actionStatus = AS_GET_LINE; }
            else           // Oeffnung fehlgeschlagen: kein Lesen -> Return = NULL
             { actionStatus = AS_IDLE;  break; }
        case AS_GET_LINE:
          if( ptrReturn = fgets(ptrTextBuf, textBufSize, fp) ) {
              iLastChar = strlen(ptrTextBuf)-1;           // Index letztes Zeichen
              // im String \n entfernen oder restl. Zeichen Dateizeile ueberlesen
              if( ptrTextBuf[iLastChar] == '\n' ) ptrTextBuf[iLastChar] = '\0';
                else while( c=fgetc(fp), c != '\n' && c != EOF ) /* leer */;
              break;                       // alles ok: gelesene Zeile zurückgeben
            }
            else /*leer*/     // Dateiende erreicht: weiter mit case AS_CLOSE_FILE
        case AS_CLOSE_FILE:
          if( fileStatus == FS_FILE_IS_OPEN )
            { fclose(fp);  fp = NULL;
              fileStatus = FS_FILE_IS_CLOSED;  actionStatus = AS_IDLE; }
          break;
        case AS_IDLE: default:                           // Ruhelage: keine Aktion
          break;
      }; // switch( actionStatus ) { ...
    
      return ptrReturn;           // alles ok: Adresse String, Fehler o. EOF: NULL
    } // getFileLine()
    
    // Ende Datei fileread.cpp
    

    -------------------------------------------------------

    Die programminterne Datenstruktur
    char-Zeigerfeld ZZF
    char* [] mit malloc oder calloc erzeugte dynamische Strings (char [ ]), Speicherplatz 1.. 80 Zeichen + '\0'
    [0] ----------> Dieses ist der Beispieltext fuer das Text-Analyse-Programm. Wir wollen\0
    [1] ----------> hoffen, dass er richtig ausgewertet wird und alle Ergebnisse korrekt\0
    [2] ----------> sind !\0
    [3] ----------> \0
    [4] ----------> Aehnliche, natuerlich kompliziertere, Analyse-Programme werden in der\0
    [5] ----------> Wissenschaft von Linguisten eingesetzt, um die Characteristika ein-\0
    [6] ----------> zelner Sprachen zu untersuchen.\0
    [7] NULL Ende des Beispieltextes, Ende der Textanalyse
    alle restlichen Feldelemente enthalten die Zeigerkonstante NULL
    [25] NULL char* ein Element mehr als maximal Textzeilen möglich sind, Zeiger immer NULL , Endeerkennung, wenn Feld voll
    Beachten: Die einzelnen dynamischen Strings [0]..[n] liegen nicht fortlaufend im Arbeitsspeicher, da die Speicherreservierung durch
    Einzelaufrufe von malloc oder calloc erfolgt. Lediglich die Zeichen eines Strings sind fortlaufend im Speicher (Feld).
    ZZF[0] char * die Adresse des ersten Zeichens von String 1
    ZZF[0][0] char das 1. Zeichen von String 1 (D)
    ZZF[1][5] char das 6. Zeichen von String 2 (n)

    ------------------------------

    hab das jetzt soweit bekommen:

    int main (void)
    {

    char *zeile[25];
    char *string;
    int i=0;

    do {
    char textbuf[81];
    getFileLine("testtext", textbuf, 81);
    int size;
    size=strlen(textbuf);
    string = (char*) malloc (size);
    string=textbuf;
    zeile[i]=string;
    printf("%d", size); /* testanzeige der stringlänge */
    puts(string);
    i++;
    } while (zeile[i] != NULL);

    getchar();
    free (string);
    return 0;
    }

    ---------------

    nur warum wiederholt sich der text bei der ausgabe am ende? sollte doch bei EOF schluss sein.



  • Du sollst die

    code
    

    Tags benutzen. Das kann doch keiner lesen ...



  • niemand hier der das versteht? brauch dringend hilfe.

    habe jetzt sowas zusammengebastelt:

    #include <stdio.h>
    #include <f:\textanalyse\fileread.h>
    #include <string.h>
    #include <stdlib.h>
    #include <conio.h>
    
    int main (void) {
    
    	char* charzeigerfeld[26];
      int j=0;
      for (j; j<=26; j++) charzeigerfeld[j] = NULL;
      char* textbuffer;
      char* string;
      int i=0;
    
      do {
    
      getFileLine("testtext", textbuffer, 81);
      string = (char*) malloc (strlen(textbuffer)+1);
      strcpy (string, textbuffer);
      strcpy (charzeigerfeld[i], string);
    
      printf("%c", charzeigerfeld[2]);  /* zum testen */
     /* puts(textbuffer); */
      i++;
      } while (i<8);
    
      getchar();
    
    	return 0;
    }
    


  • #include <stdio.h>
    #include <f:\textanalyse\fileread.h> // hier keine <> sondern "" benutzen
    #include <string.h>
    #include <stdlib.h>
    #include <conio.h>
    
    int main (void) {
    
    	char* charzeigerfeld[26];
      int j=0;
      for (j; j<=26; j++) charzeigerfeld[j] = NULL; // <26, nicht <= 26, sonst schreibst du ueber die grenze
      char* textbuffer;
      char* string;
      int i=0;
    
      do {
    
      getFileLine("testtext", textbuffer, 81); // die funktion kenne ich nicht. benutze fopen mit fgets und fclose
      string = (char*) malloc (strlen(textbuffer)+1);
      strcpy (string, textbuffer);
      strcpy (charzeigerfeld[i], string);
    
      printf("%c", charzeigerfeld[2]);  // sollte nicht funktionieren, weil czf[2] ein zeiger ist. du willst vielleicht czf[i][2]
     /* puts(textbuffer); */
      i++;
      } while (i<8);
    
      getchar();
    
    	return 0;
    }
    

    wenn du nur eine datei einlesen willst, geht das wesentlich besser mit fgets und ein bisschen realloc fuer das zeilenarray und die zeilen selbst...

    mach mal kuerzere variablennamen, die keine typbezeichnungen enthalten.



  • das sieht im moment so aus:

    #include <stdio.h>
    #include <f:\textanalyse\fileread.h>
    #include <string.h>
    #include <stdlib.h>
    #include <conio.h>
    
    char filename (int* ende);
    char read (char* zeigerfeld[26]);
    
    int main (void) {
    	int progende=0;
    
    	char* zfeld[26];
    	do  {
    
    		filename (&progende);
    		read (zfeld);
    
    	} while(progende==0);
    
      getchar();
    
    	return 0;
    }
    /******************************************************************************/
    
    char filename (int* ende) {
    	printf("[e=Ende, Return=TESTTEXT] : ");
    	char eingabe;
    	scanf(" %c", &eingabe);
    	if (eingabe=='e') *ende=1;
      return (*ende);
    }
    /******************************************************************************/
    char read (char* zeigerfeld[26]) {
    
    /*char* zeigerfeld[26];*/
      int j=0;
      for (j; j<26; j++) zeigerfeld[j] = NULL;
    
      int i=0;
      char textbuffer[81];
      do {
      	getFileLine("testtext", textbuffer, 81);
      	if (textbuffer==NULL) i=26;
    
     	 int a;
    	  a=strlen(textbuffer);
    		printf("%d", a);
    
    	  zeigerfeld[i] = (char*) calloc (strlen(textbuffer)+1, sizeof (char));
    	  strcpy (zeigerfeld[i], textbuffer);
    	  i++;
      } while (i<26);
      return (*zeigerfeld[26]);
    }
    

    das unterprogramm getfileline ist in dem quelltext oben in fileread.h und / .cpp drin. ich muss keine datei selbst öffnen.
    ich werd noch verrückt. das programm gibt mir den halben arbeitsspeicher aus, sobald ich was anzeigen will. irgendwie versteh ich den ganzen zusammenhang zwischen zeigern und strings und feldern nicht glaub ich.





  • ja danke, aber das wäre nicht die erste seite die ich gelesen habe!



  • Wie gross muss man den textbuffer wählen. Eine Datei Zeile kann doch länger als z.B 81 Zeichen sein oder?
    Gibt es eine Funktion um die Anzahl der Zeichen pro Zeile zu bekommen?



  • > Wie gross muss man den textbuffer wählen.
    beliebig

    > Eine Datei Zeile kann doch länger als z.B 81 Zeichen sein oder?
    ja

    > Gibt es eine Funktion um die Anzahl der Zeichen pro Zeile zu bekommen?
    nein und das ist gut so. wenn die zeile nicht reinpasst, meldet sich fgets schon und dann macht man eben einen groesseren puffer und liest weiter.
    c ist low level, also ist es genau das, was man erwarten sollte: ein portabler assembler.



  • ich hab jetzt einfach geschireben, dass er 81 zeichen holen soll. erst dann kann man ja mit strlen prüfen, wie lang die zeile ist. jedenfalls denk ich mir das so. das getfileline is von unserem prof vorgegeben.

    hier mal mein jetziger stand. funktioniert gar nicht.

    #include <stdio.h>
    #include <f:\textanalyse\fileread.h>
    #include <string.h>
    #include <stdlib.h>
    #include <conio.h>
    
    char filename (int* ende, char* eingabe);
    char read (char* zeigerfeld[26], char* file[81]);
    
    int main (void) {
    	int progende=0;
    
    	char zfeld[26];
    	do  {
        char filename;
    		filename (&progende, &filename);
    		read (&zfeld, filename);
    
    	} while(progende==0);
    
      getchar();
    
    	return 0;
    }
    /******************************************************************************/
    
    char filename (int* ende, char* eingabe) {
    	printf("[e=Ende, Return=TESTTEXT] : ");
    	scanf(" %c", &eingabe);
    	if (eingabe=='e') *ende=1;
      	else if (eingabe=='return') *eingabe="testtext";
    
      return (*ende, *eingabe);
    }
    /******************************************************************************/
    char read (char* zeigerfeld[26], char* file[81]) {
      int j=0;
      for (j; j<=26; j++) zeigerfeld[j] = NULL;
    
      int i=0;
      char textbuffer[81];
      do {
      	if (NULL == getFileLine(file, textbuffer, 81)) i=26;
    
     	  int a;
    	  a=strlen(textbuffer);
    		printf("%d", a);
    
    	  zeigerfeld[i] = (char*) calloc (strlen(textbuffer)+1, sizeof (char));
    	  strcpy (zeigerfeld[i], textbuffer);
    	  i++;
      } while (i<26);
      return (*zeigerfeld[26]);
    }
    


  • hier mal mein jetziger stand. funktioniert gar nicht.

    das haettest du jetzt nicht sagen duerfen. lies das:
    http://www.fefe.de/ccc/#fragen
    http://www.lugbz.org/documents/smart-questions_de.html



  • c.rackwitz schrieb:

    nein und das ist gut so. wenn die zeile nicht reinpasst, meldet sich fgets schon und dann macht man eben einen groesseren puffer und liest weiter.
    c ist low level, also ist es genau das, was man erwarten sollte: ein portabler assembler.

    Also so wie ich die Hilfe versteh gibt fgets keine Fehlermeldung zurück wenn die Zeile länger als der buffer ist. richtig?

    Beschreibung

    Liest einen String aus einem Stream.
    fgets liest einen String aus stream in den durch s angegebenen String und bricht ab, wenn entweder ein Zeilenvorschub (\n) gelesen wird oder n-1 Zeichen gelesen wurden. Der Zeilenvorschub wird am Ende von s gespeichert. Anschließend hängt fgets automatisch ein Nullzeichen (\0) an, um das Ende des Strings zu markieren.

    Rückgabewert

    fgets liefert bei fehlerfreier Ausführung den durch s bezeichneten String zurück. Bei Erreichen des Dateiendes oder im Fehlerfall ist der Rückgabewert NULL.

    Was ich auch noch angedacht habe ist auslesen mit fgetc. Dann könnte ich ja mit die grööse des Strings immer anpassen.



  • naja, wär trotzdem schön, wenn da jemand was an fehlern erkennen würde.



  • http://www.dinkumware.com/manuals/reader.aspx?b=c/&h=stdio.html#fgets

    The function reads characters from the input stream stream and stores them in successive elements of the array beginning at s and continuing until it stores n-1 characters, stores an NL character, or sets the end-of-file or error indicators. If fgets stores any characters, it concludes by storing a null character in the next element of the array. It returns s if it stores any characters and it has not set the error indicator for the stream; otherwise, it returns a null pointer. If it sets the error indicator, the array contents are indeterminate.

    wenn buffer[strlen(buffer)-1] == '\n' || feof(datei) dann hast du eine ganze zeile, sonst musst du nochmal lesen.



  • das ist ja ganz schön, aber ich bekomme ja eine ganze zeile durch getfileline übergeben.

    "Das Lesen von jeweils einer Zeile aus der Textdatei erfolgt mit dem gelieferten
    Unterprogramm GetFileLine, das sich in der Programm-Bibliothek fileread.h/cpp
    befindet.
    char* GetFileLine( char* PtrFileName, char*PtrTextBuf, int TextBufSize );
    Die Funktion liefert bei jedem Aufruf eine Zeile der Textdatei. Als Rückgabewert wird ein
    Zeiger auf das erste Zeichen der Textzeile, bzw. bei Öffnungsfehler oder Dateiende die
    Konstante NULL geliefert. "



  • dann hast du ja keine probleme mehr mit fgets.
    aber den speicher fuer die zeile musst du trotzdem bereitstellen, weil GetFileLine() den ja haben will.
    und wenn du zu wenig gibst, dann hast du eben nicht die ganze zeile.

    dein prof hat entweder unausgereifte lehrmethoden oder ist inkompetent. dafuer kannst du nichts und es ist schade, dass du mit seinen macken (wie z.b. GetFileLine()) leben musst.



  • Wenn du ein Copy&paste Lösung willst geh doch zu fit-for-study.de

    wenn buffer[strlen(buffer)-1] == '\n' || feof(datei) dann hast du eine ganze zeile, sonst musst du nochmal lesen.

    Müsste es nicht so sein?

    const buffersize=100;
    char *textpuffer;
    
    textpuffer = (char*) calloc(buffersize, sizeof(char));
    fgets(textpuffer, buffersize, FilePointer)
    if (strlen(textpuffer)+1==buffersize) && (textpuffer[strlen(textpuffer)]!='\n')  //Zeile ist noch länger
    


  • Gandalfus schrieb:

    Müsste es nicht so sein?

    nein. buffer[strlen(buffer)] ist immer '\0'. du willst strlen(buffer)-1

    statt calloc() waere malloc() besser, da die initialisierung ueberfluessig ist.


Anmelden zum Antworten