Zeile für Zeile eine Textdatei in C durchgehen

Lesezeit: 6 Minuten

Ich habe an einer kleinen Übung für meine CIS-Klasse gearbeitet und bin sehr verwirrt über die Methoden, die C verwendet, um aus einer Datei zu lesen. Alles, was ich wirklich tun muss, ist, eine Datei Zeile für Zeile durchzulesen und die aus jeder Zeile gesammelten Informationen zu verwenden, um ein paar Manipulationen vorzunehmen. Ich habe versucht, die Getline-Methode und andere ohne Glück zu verwenden. Mein Code ist derzeit wie folgt:

int main(char *argc, char* argv[]){
      const char *filename = argv[0];
      FILE *file = fopen(filename, "r");
      char *line = NULL;

      while(!feof(file)){
        sscanf(line, filename, "%s");
        printf("%s\n", line);
      }
    return 1;
}

Im Moment erhalte ich einen Seg-Fehler mit der sscanf-Methode und bin mir nicht sicher, warum. Ich bin ein totaler C-Noob und frage mich nur, ob mir etwas im Großen und Ganzen gefehlt hat. Vielen Dank

  • Dieser Code sollte nicht einmal kompiliert werden. sscanf(line, filename, "%s"); sollte sein sscanf(line, file, "%s");

    – Mawg sagt, Monica wieder einzusetzen

    10. August 2016 um 14:50 Uhr

  • Beachten Sie, dass while (!feof(file)) ist immer falsch.

    – Jonathan Leffler

    8. Mai 2017 um 21:17 Uhr

  • Mögliches Duplikat von C liest Datei Zeile für Zeile

    – Ciro Santilli OurBigBook.com

    24. November 2017 um 16:37 Uhr

Benutzeravatar von AProgrammer
Ein Programmierer

So viele Probleme in so wenigen Zeilen. Einiges habe ich wohl vergessen:

  • argv[0] ist der Programmname, nicht das erste Argument;
  • Wenn Sie eine Variable einlesen möchten, müssen Sie deren Speicher zuweisen
  • feof wird nie wiederholt, man wiederholt eine IO-Funktion, bis sie fehlschlägt, feof dient dann dazu, den Grund des Fehlers zu ermitteln,
  • sscanf ist da, um eine Zeile zu analysieren, wenn Sie eine Datei analysieren möchten, verwenden Sie fscanf,
  • “%s” stoppt am ersten Leerzeichen als Format für die ?scanf-Familie
  • um eine Zeile zu lesen, ist die Standardfunktion fgets,
  • Zurückgeben von 1 von main bedeutet Fehler

So

#include <stdio.h>

int main(int argc, char* argv[])
{
    char const* const fileName = argv[1]; /* should check that argc > 1 */
    FILE* file = fopen(fileName, "r"); /* should check the result */
    char line[256];

    while (fgets(line, sizeof(line), file)) {
        /* note that fgets don't strip the terminating \n, checking its
           presence would allow to handle lines longer that sizeof(line) */
        printf("%s", line); 
    }
    /* may check feof here to make a difference between eof and io failure -- network
       timeout for instance */

    fclose(file);

    return 0;
}

  • nicht vergessen fclose(file) vor der Rückkehr.

    – Vivisidea

    18. Februar 2014 um 9:46 Uhr

  • das fclose(file) ist eigentlich nicht nötig, da es in passiert main und es schließt automatisch alle geöffneten Dateipuffer.

    – Leandros

    9. August 2015 um 13:52 Uhr

  • @Leandros, es ist immer besser, auf Nummer sicher zu gehen, als sich zu entschuldigen!

    – Vallentin

    29. Juli 2016 um 21:26 Uhr

  • Für Anfänger immer noch gut zu haben, denn manchmal ist es sogar am Ende der Main notwendig. FILE* Objekte werden in C gepuffert, wenn also Daten in eine Datei geschrieben wurden und fclose wurde nicht aufgerufen, einige der Daten werden möglicherweise nicht geleert.

    – rovaughn

    1. September 2016 um 17:20 Uhr

  • Hallo, @alecRN: Bist du sicher? AFAIK, die gepufferte Ausgabe eines Streams wird automatisch geleert, wenn das Programm durch den Aufruf von exit beendet wird (siehe: gnu.org/software/libc/manual/html_node/Flushing-Buffers.html ), und das Betriebssystem entscheidet, wann es geleert wird (kann fsync aufrufen). Es gibt einen impliziten Aufruf von exit_group am Ende der Ausführung, Sie können ihn mit strace und nm sehen. Ich nehme an, es wird nicht von gcc hinzugefügt, weil es kein solches Symbol gibt, wahrscheinlich wird es von der Laufzeit hinzugefügt. Sogar _exit schließt die offenen Dateideskriptoren. Wie auch immer, ich stimme Ihnen zu, dass es eine gute Angewohnheit ist, geöffnete Dateien explizit zu schließen /Ángel

    – Engel

    10. Januar 2017 um 9:02 Uhr


Benutzeravatar von Abrixas2
Abrixas2

Um eine Zeile aus einer Datei zu lesen, sollten Sie die verwenden fgets Funktion: Liest eine Zeichenfolge aus der angegebenen Datei bis entweder zu einem Zeilenumbruchzeichen oder EOF.

Die Verwendung von sscanf in Ihrem Code würde überhaupt nicht funktionieren, wie Sie es verwenden filename als Ihre Formatzeichenfolge zum Lesen line in ein konstantes Zeichenfolgenliteral %s.

Der Grund für SEGV ist, dass Sie in den nicht zugeordneten Speicher schreiben, auf den von zeigt line.

Benutzeravatar von Basile Starynkevitch
Basile Starynkevitch

Zusätzlich zu den anderen Antworten könnten Sie eine aktuelle C-Bibliothek (Posix 2008-kompatibel) verwenden getline. Siehe diese Antwort (auf eine verwandte Frage).

Benutzeravatar von Alex Reynolds
Alex Reynolds

Angenommen, Sie haben es mit einem anderen Trennzeichen zu tun, z. B. a \t Tab statt a \n Neue Zeile.

Ein allgemeinerer Ansatz für Trennzeichen ist die Verwendung von getc()die jeweils ein Zeichen erfasst.

Beachten Sie, dass getc() gibt ein zurück intdamit wir mit auf Gleichheit testen können EOF.

Zweitens definieren wir ein Array line[BUFFER_MAX_LENGTH] des Typs charum bis zu speichern BUFFER_MAX_LENGTH-1 Zeichen auf dem Stapel (wir müssen das letzte Zeichen für a speichern \0 Abschlusszeichen).

Die Verwendung eines Arrays vermeidet die Notwendigkeit der Verwendung malloc und free um einen Zeichenzeiger der richtigen Länge auf dem Heap zu erstellen.

#define BUFFER_MAX_LENGTH 1024

int main(int argc, char* argv[])
{
    FILE *file = NULL;
    char line[BUFFER_MAX_LENGTH];
    int tempChar;
    unsigned int tempCharIdx = 0U;

    if (argc == 2)
         file = fopen(argv[1], "r");
    else {
         fprintf(stderr, "error: wrong number of arguments\n"
                         "usage: %s textfile\n", argv[0]);
         return EXIT_FAILURE;
    }

    if (!file) {
         fprintf(stderr, "error: could not open textfile: %s\n", argv[1]);
         return EXIT_FAILURE;
    }

    /* get a character from the file pointer */
    while(tempChar = fgetc(file))
    {
        /* avoid buffer overflow error */
        if (tempCharIdx == BUFFER_MAX_LENGTH) {
            fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n");
            return EXIT_FAILURE;
        }

        /* test character value */
        if (tempChar == EOF) {
            line[tempCharIdx] = '\0';
            fprintf(stdout, "%s\n", line);
            break;
        }
        else if (tempChar == '\n') {
            line[tempCharIdx] = '\0';
            tempCharIdx = 0U;
            fprintf(stdout, "%s\n", line);
            continue;
        }
        else
            line[tempCharIdx++] = (char)tempChar;
    }

    return EXIT_SUCCESS;
}

Wenn Sie a verwenden müssen char *dann können Sie diesen Code immer noch verwenden, aber Sie strdup() das line[] Array, sobald es mit der Eingabe einer Zeile gefüllt ist. Du musst free diese duplizierte Zeichenfolge, sobald Sie damit fertig sind, oder Sie erhalten ein Speicherleck:

#define BUFFER_MAX_LENGTH 1024

int main(int argc, char* argv[])
{
    FILE *file = NULL;
    char line[BUFFER_MAX_LENGTH];
    int tempChar;
    unsigned int tempCharIdx = 0U;
    char *dynamicLine = NULL;

    if (argc == 2)
         file = fopen(argv[1], "r");
    else {
         fprintf(stderr, "error: wrong number of arguments\n"
                         "usage: %s textfile\n", argv[0]);
         return EXIT_FAILURE;
    }

    if (!file) {
         fprintf(stderr, "error: could not open textfile: %s\n", argv[1]);
         return EXIT_FAILURE;
    }

    while(tempChar = fgetc(file))
    {
        /* avoid buffer overflow error */
        if (tempCharIdx == BUFFER_MAX_LENGTH) {
            fprintf(stderr, "error: line is too long. increase BUFFER_MAX_LENGTH.\n");
            return EXIT_FAILURE;
        }

        /* test character value */
        if (tempChar == EOF) {
            line[tempCharIdx] = '\0';
            dynamicLine = strdup(line);
            fprintf(stdout, "%s\n", dynamicLine);
            free(dynamicLine);
            dynamicLine = NULL;
            break;
        }
        else if (tempChar == '\n') {
            line[tempCharIdx] = '\0';
            tempCharIdx = 0U;
            dynamicLine = strdup(line);
            fprintf(stdout, "%s\n", dynamicLine);
            free(dynamicLine);
            dynamicLine = NULL;
            continue;
        }
        else
            line[tempCharIdx++] = (char)tempChar;
    }

    return EXIT_SUCCESS;
}

1415880cookie-checkZeile für Zeile eine Textdatei in C durchgehen

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy