从stdin读取未知长度的未知行数

时间:2017-10-09 22:57:27

标签: c io stdin fgets

我对使用 stdin fgets 读取输入相对较新,我正在尝试阅读 int max_length = 50; char lines[max_length][max_length]; char current_line[max_length]; int idx = 0; while(fgets(current_line, max_length, stdin) != NULL) { strcopy(lines[idx], current_line); idx++; } 的输入。

首先,我考虑阅读最多50行,每行最多50个字符,并且有类似的内容:

lines

上面的代码片段成功读取输入并将其存储到{{1}}数组中,我可以对其进行排序和打印。

我的问题是如何处理未知数量的行,每行都有未知数量的字符? (请记住,我必须对线条进行排序并打印出来)。

2 个答案:

答案 0 :(得分:1)

查看找到here的GetString函数。

答案 1 :(得分:1)

虽然已经回答了这个问题的许多不同变体,但是如何解决这个问题可以使用一个段落。遇到这个问题时,无论您使用哪种库或POSIX函数组合,方法都是相同的。

基本上,您将动态分配合理数量的字符来保存每一行。 POSIX getline将自动为您执行此操作,使用fgets您只需读取一个充满字符的固定缓冲区并附加它们(根据需要重新分配存储),直到读取'\n'字符(或已达到EOF

如果使用getline,则必须为其分配内存,并复制已填充的缓冲区。否则,您将在每次读取新行时覆盖以前的行,当您尝试free每一行时,您可能会反复尝试释放双重免费或损坏的SegFault相同的记忆块。

您可以使用strdup简单地复制缓冲区。但是,由于strdup分配了存储空间,因此在将指向新内存块的指针指向行集合之前,应验证成功分配。

要访问每一行,您需要一个指向每行开头的指针(每行的内存块)。通常使用指向char 指针的指针。 (例如char **lines;)内存分配通常通过分配一些合理数量的指针来开始处理,跟踪你使用的数字,当你达到你分配的数字时,你realloc和双指针的数量。

与每次阅读一样,您需要 验证 每次内存分配。 (每个malloccallocrealloc)您还需要通过内存错误检查程序(例如{{}运行程序来验证程序使用您分配的内存的方式。 1}} for Linux)。它们易于使用,仅valgrind

将这些部分组合在一起,您可以执行与以下类似的操作。以下代码将读取作为程序的第一个参数提供的文件名中的所有行(如果未提供参数,则默认从valgrind yourexename读取)并将行号和行打印到stdin(保留该行)记住,如果你在50,000行文件上运行它)

stdout

如果您没有#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,则可以轻松实现每项。网站上有多个例子。如果找不到,请告诉我。如果您还有其他问题,请与我联系。