Es gibt viele Möglichkeiten, dieses Problem zu nähern. Deklarieren Sie entweder ein statisches 2D-Array oder ein char (z. B. char lines[40][50] = {{""}};
) oder deklarieren Sie einen -Zeiger auf ein Array vom Typ char [50], das wahrscheinlich am einfachsten für die dynamische Zuweisung ist. Mit diesem Ansatz benötigen Sie nur eine einzige Zuweisung. Bei konstantem MAXL = 40
und MAXC = 50
, müssen Sie einfach:
char (*lines)[MAXC] = NULL;
...
lines = malloc (MAXL * sizeof *lines);
lesen jede Zeile mit fgets
ist eine einfache Aufgabe:
while (i < MAXL && fgets (lines[i], MAXC, fp)) {...
Wenn Sie fertig sind, alles, was Sie tun müssen, ist free (lines);
Setzt man die Stücke
#include <stdio.h>
#include <stdlib.h>
enum { MAXL = 40, MAXC = 50 };
int main (int argc, char **argv) {
char (*lines)[MAXC] = NULL; /* pointer to array of type char [MAXC] */
int i, n = 0;
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* valdiate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
if (!(lines = malloc (MAXL * sizeof *lines))) { /* allocate MAXL arrays */
fprintf (stderr, "error: virtual memory exhausted 'lines'.\n");
return 1;
}
while (n < MAXL && fgets (lines[n], MAXC, fp)) { /* read each line */
char *p = lines[n]; /* assign pointer */
for (; *p && *p != '\n'; p++) {} /* find 1st '\n' */
*p = 0, n++; /* nul-termiante */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
/* print lines */
for (i = 0; i < n; i++) printf (" line[%2d] : '%s'\n", i + 1, lines[i]);
free (lines); /* free allocated memory */
return 0;
}
Anmerkung: zusammen, können Sie so etwas wie tun dir ein Ebenso sollte überprüft werden, ob die gesamte Zeile jedes Mal von fgets
gelesen wurde. (Angenommen, Sie hatten eine lange Reihe von mehr als 38 Zeichen in der Datei). Dazu prüfen Sie, ob *p
'\n'
vor dem Überschreiben mit dem nullenden Zeichen ist. (z.B. if (*p != '\n') { int c; while ((c = getchar()) != '\n' && c != EOF) {} }
). Dies stellt sicher, dass der nächste Lesevorgang mit fgets
mit der nächsten Zeile statt mit den restlichen Zeichen in der aktuellen Zeile beginnt.
Um die Prüfung sind Sie etwas ähnliches wie die folgenden tun könnten (Anmerkung: ich i
-n
die Leseschleifenzähler geändert, um die Notwendigkeit für die Zuordnung n = i;
nach der Leseschleife zu beseitigen).
while (n < MAXL && fgets (lines[n], MAXC, fp)) { /* read each line */
char *p = lines[n]; /* assign pointer */
for (; *p && *p != '\n'; p++) {} /* find 1st '\n' */
if (*p != '\n') { /* check line read */
int c; /* discard remainder of line with getchar */
while ((c = fgetc (fp)) != '\n' && c != EOF) {}
}
*p = 0, n++; /* nul-termiante */
}
Es liegt an Ihnen, ob Sie den Rest der Zeilen, die die Länge Ihres Arrays überschreiten, verwerfen oder behalten. Es ist jedoch eine gute Idee, immer zu überprüfen. (Die Textzeilen in meinem Beispiel Eingang unten auf 17 Zeichen beschränkt, so gibt es keine Möglichkeit, eine Linie lang war, aber Sie können in der Regel nicht die Zeilenlänge garantieren.
Beispiel Eingabe
$ cat dat/40lines.txt
line of text - 1
line of text - 2
line of text - 3
line of text - 4
line of text - 5
line of text - 6
...
line of text - 38
line of text - 39
line of text - 40
Beispiel Verwendung/Output
$ ./bin/fgets_ptr2array <dat/40lines.txt
line[ 1] : 'line of text - 1'
line[ 2] : 'line of text - 2'
line[ 3] : 'line of text - 3'
line[ 4] : 'line of text - 4'
line[ 5] : 'line of text - 5'
line[ 6] : 'line of text - 6'
...
line[38] : 'line of text - 38'
line[39] : 'line of text - 39'
line[40] : 'line of text - 40'
nun auch eine der Längenprüfung in Code und eine lange Leitung mit dem Eingang, zB:
Führen Sie das Programm erneut aus, und Sie können bestätigen, dass Sie jetzt vor langen Zeilen in der Datei geschützt sind, die Ihr sequentielles Lesen von Zeilen aus der Datei muckt.
dynamisch Neuverteilung lines
Wenn Sie eine unbekannte Anzahl von Zeilen in der Datei haben, und Sie Ihre anfängliche Zuteilung von 40
in lines
erreichen, dann alles, was Sie tun müssen, lesen zusätzliche Leitungen zu halten ist realloc
Speicher für lines
. Zum Beispiel:
int i, n = 0, maxl = MAXL;
...
while (fgets (lines[n], MAXC, fp)) { /* read each line */
char *p = lines[n]; /* assign pointer */
for (; *p && *p != '\n'; p++) {} /* find 1st '\n' */
*p = 0; /* nul-termiante */
if (++n == maxl) { /* if limit reached, realloc lines */
void *tmp = realloc (lines, 2 * maxl * sizeof *lines);
if (!tmp) { /* validate realloc succeeded */
fprintf (stderr, "error: realloc - virtual memory exhausted.\n");
break; /* on failure, exit with existing data */
}
lines = tmp; /* assign reallocated block to lines */
maxl *= 2; /* update maxl to reflect new size */
}
}
Jetzt spielt es keine Rolle, wie viele Zeilen in der Datei sind, halten Sie einfach lines
, bis die ganze Dateien gelesen wird Umschichtungen vorzunehmen, oder Sie laufen aus dem Speicher. (Anmerkung: zur Zeit ordnet der Code zweimal den aktuellen Speicher für lines
auf jeder Umschichtung Sie sind frei, so viel hinzuzufügen, oder so wenig wie Sie möchten zum Beispiel Sie maxl + 40
zuordnen könnte einfach 40
jedes Mal mehr Zeilen zuzuordnen
...
Beispiel Eingabe
$ cat dat/80lines.txt
line of text - 1
line of text - 2
...
line of text - 79
line of text - 80
Beispiel Verwendung/Output
$ ./bin/fgets_ptr2array_realloc <dat/80lines.txt
line[ 1] : 'line of text - 1'
line[ 2] : 'line of text - 2'
...
line[79] : 'line of text - 79'
line[80] : 'line of text - 80'
Schauen Sie vorbei und lassen Sie mich wissen, wenn Sie irgendwelche Fragen haben.
Ordnen Sie Speicher für das Zeigerfeld selbst mit 'malloc' zu, wenn es Ihr Limit erreicht, erweitern Sie es mit' realloc' und aktualisieren Sie das Limit ... –
Haben wir eine Bestandsantwort dafür? Es wird ca. gefragt. 3x/Tag. –
@kata zur Seite: Denken Sie daran, dass 'fgets' eine 'newline' am Ende von' line' behalten soll. –