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:
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
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
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.
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).
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;
}
14158800cookie-checkZeile für Zeile eine Textdatei in C durchgehenyes
Dieser Code sollte nicht einmal kompiliert werden.
sscanf(line, filename, "%s");
sollte seinsscanf(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