/* 08May24: Eine Variation von der tail.c, was beliebig-lange Zeilen * unterstützen sollte. Mehr Kommentare in der Datei. */ #include #include #include #define N 10 int main() { char *lines[N] = {}; unsigned i = 0; for (;;) { /* Hier legen wir den Speicher nicht auf dem Stack an, * sondern lesen direkt auf Halden-Speicher. Der Vorteil * davon, ist das wir den gültigen Speicher dynamisch * erweitern können. */ unsigned len = 1024; /* Zum Nachdenken: Wie kann man diesen malloc(3) Aufruf hier * vergessen. */ char *line = malloc(len); if (NULL == line) { perror("malloc"); exit(EXIT_FAILURE); } for (unsigned j = 0;; j++) { /* Sobald wir erkennen, dass wir nicht genug Speicher * haben für die Zeile: */ if (j >= len) { /* Hier vergrößern wir den Speicher linear, aber * man kann auch schauen wie das Verhalten sich * verändert wenn man einen anderen Ansatz nimmt. */ len += 1024; line = realloc(line, len); if (NULL == line) { perror("realloc"); exit(EXIT_FAILURE); } } /* Anstatt mit fgets(3) zu lesen, machen wir hier ein * Beispiel wie man Zeichenweise einlesen kann. Achtet * auf den Rückgabe-Typ von fgetc(3)! */ int c = fgetc(stdin); if (c == EOF) { if (ferror(stdin)) { perror("fgetc"); exit(EXIT_FAILURE); } else { /* Goto ist hier IMO akzeptabel, weil man * nach vorne springt und nur ein "break" * nachbaut. */ goto end_of_file; } } line[j] = c; if (line[j] == '\n') { /* Hier brechen wir die "Zeile-Einlesen" Schleife. */ break; } } free(lines[i % N]); lines[i % N] = line; if (lines[i % N] == NULL) { perror("strdup"); exit(EXIT_FAILURE); } i++; } end_of_file: for (unsigned j = 0; j < N; j++) { if (lines[(i + j) % N] == NULL) break; fputs(lines[(i + j) % N], stdout); free(lines[(i + j) % N]); } if (EOF == fflush(stdout)) { perror("fflush"); exit(EXIT_FAILURE); } return EXIT_FAILURE; }