虽然已经回答了这个问题的许多不同变体,但如何解决这个问题的考虑可以使用一个段落。遇到此问题时,无论您使用哪种库或 POSIX 函数组合,方法都是相同的。
基本上,您将动态分配合理数量的字符来容纳每一行。 POSIX getline 将自动为您执行此操作,使用 fgets 您可以简单地读取一个充满字符的固定缓冲区并附加它们(根据需要重新分配存储),直到读取 '\n' 字符(或达到 EOF)
如果你使用getline,那么你必须分配内存,并复制填充的缓冲区。否则,您将在读取每个新行时覆盖以前的行,并且当您尝试free 每一行时,您可能会在反复尝试释放同一块时出现 double-free or corruption 的 SegFault内存。
您可以使用strdup 简单地复制缓冲区。但是,由于strdup 分配存储空间,您应该先验证分配是否成功,然后再将指向新内存块的指针分配给您的行集合。
要访问每一行,您需要一个指向每一行开头的指针(保存每一行的内存块)。通常使用 指向 char 指针的指针。 (例如char **lines;)内存分配通常通过分配一些合理数量的指针开始处理,跟踪您使用的数字,当您达到分配的数字时,您realloc并将指针数量加倍.
与每次读取一样,您需要验证每个内存分配。 (每个malloc、calloc 或realloc)您还需要通过内存错误检查程序(例如Linux 的valgrind)运行程序来验证您的程序使用您分配的内存的方式。它们使用简单,只需valgrind yourexename。
将这些部分放在一起,您可以执行类似于以下的操作。以下代码将从作为程序的第一个参数提供的文件名中读取所有行(如果没有提供参数,则默认情况下从 stdin 读取)并将行号和行打印到 stdout(如果您在 50,000 行文件上运行它)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NPTR 8
int main (int argc, char **argv) {
size_t ndx = 0, /* line index */
nptrs = NPTR, /* initial number of pointers */
n = 0; /* line alloc size (0, getline decides) */
ssize_t nchr = 0; /* return (no. of chars read by getline) */
char *line = NULL, /* buffer to read each line */
**lines = NULL; /* pointer to pointer to each line */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
/* allocate/validate initial 'nptrs' pointers */
if (!(lines = calloc (nptrs, sizeof *lines))) {
fprintf (stderr, "error: memory exhausted - lines.\n");
return 1;
}
/* read each line with POSIX getline */
while ((nchr = getline (&line, &n, fp)) != -1) {
if (nchr && line[nchr - 1] == '\n') /* check trailing '\n' */
line[--nchr] = 0; /* overwrite with nul-char */
char *buf = strdup (line); /* allocate/copy line */
if (!buf) { /* strdup allocates, so validate */
fprintf (stderr, "error: strdup allocation failed.\n");
break;
}
lines[ndx++] = buf; /* assign start address for buf to lines */
if (ndx == nptrs) { /* if pointer limit reached, realloc */
/* always realloc to temporary pointer, to validate success */
void *tmp = realloc (lines, sizeof *lines * nptrs * 2);
if (!tmp) { /* if realloc fails, bail with lines intact */
fprintf (stderr, "read_input: memory exhausted - realloc.\n");
break;
}
lines = tmp; /* assign reallocted block to lines */
/* zero all new memory (optional) */
memset (lines + nptrs, 0, nptrs * sizeof *lines);
nptrs *= 2; /* increment number of allocated pointers */
}
}
free (line); /* free memory allocated by getline */
if (fp != stdin) fclose (fp); /* close file if not stdin */
for (size_t i = 0; i < ndx; i++) {
printf ("line[%3zu] : %s\n", i, lines[i]);
free (lines[i]); /* free memory for each line */
}
free (lines); /* free pointers */
return 0;
}
如果您没有getline 或strdup,您可以轻松实现每一个。网站上有多个示例。如果找不到,请告诉我。如果您还有其他问题,也请告诉我。