fscanf // Zeilenweises Einlesen aus einer .txt Datei



  • Hallo liebe Gemeinde,

    ich versuche gerade ein Programm zu entwickeln, welches eine .txt Datei zeilenweise einliest und in eine struct einfügt. Aber soweit komme ich gar nicht. Ich bin schon mit dem Debugger über meinen Code gegangen und gesehen, dass die Adresse des Pointers auf die .txt zeigt. Aber irgendwie funktioniert die Methode fscanf nicht. Diese soll eigentlich pro Zeile zwei Strings und zwei Integer Variablen bekommen. Die fscanf Methode steht relativ weit unten in Zeile 35.

    Dies ist mein Code in der main:

    int main(void) {
    
        char* titel;
        int release;
        int length;
        char* regisseur;
    
        char filename[FILENAME_MAX];
        char line[MAXLINE];
        FILE *filepointer;
        size_t p;
    
        printf("Which File should be opend? (Needs to be in the same directory): ");
        fgets(filename, FILENAME_MAX, stdin);
    
        //Entfernt new line und setzt end of line 
        p = strlen(filename);
        filename[p-1] = '\0';
    
        filepointer = fopen(filename, "r");
    
        if(filepointer == 0) {
            printf("File can´t be opend!\n");
            return EXIT_FAILURE;
    
        } else {
    
            //Zählt die Zeilen in der .txt Datei 
            while(fgets(line, MAXLINE, filepointer)) {
                getlinenumbers = getlinenumbers+1;
            }
    
            //Erstellt (getlinenumbers) mal die movie struct. Liest nun Zeilenweise die .txt ein. Bekommt die Infos zu dem Film und fügt diese in die movie struct ein.  
            movie* input_movie[getlinenumbers];
            while(fscanf(filepointer, "%[^;];%d[^;];%d[^;];%[^;]", titel, &release, &length, regisseur) != EOF) {
                input_movie[i] = new_movie(titel, release, length, regisseur);
                i++;
            }
    
            for(int j = 0; j<i; j++) {
                printf("%s, %d, %d, %s", input_movie[j]->titel, input_movie[j]->release, input_movie[j]->length, input_movie[j]->regisseur);
            }
    
        }
        return EXIT_SUCCESS;
    }
    

    Vielleicht kann mir jemand helfen oder Tipps geben, was ich genau falsch mache.

    Vielen Dank schonmal im Voraus!



  • Kieselstein schrieb:

    was ich genau falsch mache.

    Alles.
    - du verwendest VLA und weißt nicht was du da tust
    - du definierst ein Array von Zeigern statt ein Array von struct
    - du zeigst die Definition von getlinenumbers und der struct nicht (siehe Forumsregeln)
    - du prüfst bei fscanf auf EOF (klassischer Anfänger und Buchautorenfehler)
    - "%d[^;]" ist Schrott, denn %d hört immer schon vor ';' auf, wenn müsste es sowieso "%d%[^;]" heißen, und sowieso besser "%d;"
    - du machst keine Längenbegrenzung für Strings bei fscanf
    - du vergisst rewind um wieder an den Dateianfang zu wechseln
    - die Fehlerbehandlung macht man mit perror UND Angabe des Dateinamens
    - du setzt das letzte Zeichen der Eingabe ohne Prüdung auf '\0'
    - dein Englisch ist auch Schrott, das heißt opened und nicht opend
    - u.v.a.m



  • scanf() ist erstmal relativ kompliziert, ja.
    Aber offensichtlich hast Du komplett falsche Vorstellung vom Formatstring. Scheinbar denkst Du eher an eine Art regulären Ausdruck.

    Nun ist nicht ganz ersichtlich, wie das Format Deiner Textdatei ist

    Film 1 ; 1999 ; 90 ; Regisseur 1
    Film 2 ; 1999 ; 91 ; Regisseur 2
    Film 3 ; 1999 ; 92 ; Regisseur 2
    Film 4 ; 1999 ; 93 ; Regisseur 3
    Film 5 ; 1999 ; 94 ; Regisseur 1
    

    So?

    Dann müsste der Formatstring:

    01. whitespaces (ws) überspringen
    02. alles, was kein ';' speichern
    03. ein ';' lesen
    04. eine Zahl speichern (ws werden bei %d übersprungen)
    05. ws überspringen
    06. ein ';' lesen
    07. eine Zahl speichern (ws werden wieder übersprungen)
    08. ws überspringen
    09. ein ';' lesen
    10. ws überspringen
    11. alles bis zum Zeilenumbruch ('\n') speichern

    das lesen jetzt noch in eine Funktion packen und schon lässt sich das ganz bequem benutzen.
    Der Formatstring sollte eigentlich verständlich sein, da wo explizit ws übersprungen werden sollen ist ein ' ' (space) im string vorhanden.
    Schau noch mal in fscanf() Dokumentation!

    int movie_read(FILE *file, struct movie *m)
    {
      static const char fmt[] = " %99[^;];%d ;%d ; %99[^\n]";
      char title[100], director[100];
      int release, length;
      int ok = fscanf(file, fmt, title, &release, &length, director)==4;
      if(!ok)
        return 0;
      movie_construct(m, title, release, length, director);
      return 1;
    }
    


  • Erstmal ein Dank an euch beiden! Vor allem die Funktion von Furble Wurble hat mir sehr geholfen. Es funktioniert nun so wie gewollt. (Übrigens war die .txt Datei genau so aufgebaut wie du es geschrieben hast.)

    Auch ein Dank an Wutz. Ein paar deiner Punkte haben mir sehr geholfen. Leider habe ich nicht wirklich Erfahrung in der C programmierung und möchte mich nochmal für die "schlechte" Frage entschuldigen.

    Eine Sache würde ich aber gerne noch hinterfragen. Du hast geschrieben, dass ich VLA benutze und nicht weiß was ich tue. Ich verstehe nicht genau wo das Problem liegt VLA zu benutzen. Warum ist das eher schlecht?

    Liebe Grüße!



  • Du kannst ja mal da rein schauen: http://www.c-plusplus.net/forum/319516-full

    Fängt harmlos an.



  • Du kannst ja mal versuchen das VLA zu vermeiden. Und auch gleich noch die Zeilenzählerei zu verbannen.

    Evtl. mit einer Funktion, die ein Array alloziert ( malloc() ) und da reinliest.
    Wird das Array nicht voll ist die Funktion fertig und gibt das Array an den User (der später free() darauf aufruft.
    Wird das Array voll, wird es vergrößert( realloc() ) und weiter eingelesen.
    Usw. bis ein Lesevorgang nicht mehr das gesamte (Rest-)Array füllt.

    Hilfreich könnte noch ein Helferlein sein:

    // liest maximal n movie Objekte aus file ein und speichert sie an der Stelle m
    // gibt die Anzahl der gespeicherten Objekte zurueck
    size_t movie_read_n(struct movie *m, size_t n, FILE *file);
    

Anmelden zum Antworten