从stdin,C读取未知数量的行

我有一个读取未知大小的标准输入的问题。 实际上它是.txt文件中的一个表,我通过调用参数'<'table.txt来获取stdin。 我的代码应如下所示:

#include  #include  int main(int argc,char *argv[]) { char words[10][1024]; int i=0; while(feof(stdin)==0) { fgets(words[i],100,stdin); printf("%s", words[i]); i++; } return 0; } 

但有问题我不知道行的nuber,在这种情况下是10(我们知道行中的字符数 – 1024)。 如果有人知道解决方案会很棒。 提前致谢。

你遇到了困扰所有新C程序员的问题之一。 如何动态分配我需要的所有内存,让自己摆脱静态限制,同时仍然跟踪我在内存中的“东西”集合。 当您需要从输入中读取未知数量的“事物”时,通常会出现此问题。 最初的选项是(1)声明一些足够大的限制来工作(击败目的),或者(2)根据需要动态分配指针。

显然,目标是(2) 。 但是,您会遇到“如何跟踪我分配的内容?”的问题。 这本身就是狗初学者的问题。 问题是, 如果我使用一堆指针动态分配,**如何迭代列表以使我的“东西”退出? 此外,您必须初始化一些初始指针数(除非使用像链接列表这样的高级数据结构),因此下一个问题是“当我用完时我该怎么办?”

通常的解决方案是分配一组初始指针,然后当达到限制时,重新分配到原始指针的两倍,然后继续。 (正如格雷森在答案中指出的那样)。

然而,还有一个技巧可以迭代列表,让你的“东西”退出 ,这是值得理解的。 是的,您可以使用malloc进行分配并跟踪所使用的指针数量,但是您可以通过最初使用calloc分配来calloc对指针列表的限制。 这不仅分配空间,还将分配的指针设置为NULL (或0)。 这允许您使用简单的while (pointer != NULL)迭代列表。 当将指针集合传递给函数等时,这提供了许多好处 。缺点(最小的一个)是您可以编写一个重新分配方案,该方案使用calloc在需要时分配新空间。 (让我变得更聪明 – 但我必须努力做到……)

您可以评估是否使用现成的malloc/realloc ,或者是否使用calloccustom reallocate function具体取决于您的要求。 无论如何,理解这两者,只需在编程工具箱中添加更多工具。

好吧,足够的jabber, 这一切的例子在哪里?

以下两个示例都只是从任何文本文件中读取所有行,并将行(带有指针索引号)打印回stdout。 两者都希望您提供文件名作为命令行上的第一个参数。 两者之间的唯一区别是第二个用calloc完成的重新分配是一个custom reallocation function 。 它们最初分配255指针,每次达到限制时指针数量加倍。 (为了好玩,你可以将MAXLINES设置为像10这样小的东西并强制重复重新分配来测试)。

main()中重新分配的第一个例子

 # include  # include  # include  #define MAXLINES 255 void free_buffer (char **buffer) { register int i = 0; while (buffer[i]) { free (buffer[i]); i++; } free (buffer); } int main (int argc, char **argv) { if (argc < 2) { fprintf (stderr, "Error: insufficient input. Usage: %s input_file\n", argv[0]); return 1; } char *line = NULL; /* forces getline to allocate space for buf */ ssize_t read = 0; /* number of characters read by getline */ size_t n = 0; /* limit number of chars to 'n', 0 no limit */ char **filebuf = NULL; char **rtmp = NULL; int linecnt = 0; size_t limit = MAXLINES; size_t newlim = 0; FILE *ifp = fopen(argv[1],"r"); if (!ifp) { fprintf(stderr, "\nerror: failed to open file: '%s'\n\n", argv[1]); return 1; } filebuf = calloc (MAXLINES, sizeof (*filebuf)); /* allocate MAXLINES pointers */ while ((read = getline (&line, &n, ifp)) != -1) /* read each line in file with getline */ { if (line[read - 1] == 0xa) { line[read - 1] = 0; read--; } /* strip newline */ if (linecnt >= (limit - 1)) /* test if linecnt at limit, reallocate */ { newlim = limit * 2; /* set new number of pointers to 2X old */ if ((rtmp = calloc (newlim, sizeof (*filebuf)))) /* calloc to set to NULL */ { /* copy original filebuf to newly allocated rtmp */ if (memcpy (rtmp, filebuf, linecnt * sizeof (*filebuf)) == rtmp) { free (filebuf); /* free original filebuf */ filebuf = rtmp; /* set filebuf equal to new rtmp */ } else { fprintf (stderr, "error: memcpy failed, exiting\n"); return 1; } } else { fprintf (stderr, "error: rtmp allocation failed, exiting\n"); return 1; } limit = newlim; /* update limit to new limit */ } filebuf[linecnt] = strdup (line); /* copy line (strdup allocates) */ linecnt++; /* increment linecnt */ } fclose(ifp); if (line) free (line); /* free memory allocated to line */ linecnt = 0; /* reset linecnt to iterate filebuf */ printf ("\nLines read in filebuf buffer:\n\n"); /* output all lines read */ while (filebuf[linecnt]) { printf (" line[%d]: %s\n", linecnt, filebuf[linecnt]); linecnt++; } printf ("\n"); free_buffer (filebuf); /* free memory allocated to filebuf */ return 0; } 

在自定义函数中重新分配的第二个示例

 # include  # include  # include  #define MAXLINES 255 /* function to free allocated memory */ void free_buffer (char **buffer) { register int i = 0; while (buffer[i]) { free (buffer[i]); i++; } free (buffer); } /* custom realloc using calloc/memcpy */ char **recalloc (size_t *lim, char **buf) { int newlim = *lim * 2; char **tmp = NULL; if ((tmp = calloc (newlim, sizeof (*buf)))) { if (memcpy (tmp, buf, *lim * sizeof (*buf)) == tmp) { free (buf); buf = tmp; } else { fprintf (stderr, "%s(): error, memcpy failed, exiting\n", __func__); return NULL; } } else { fprintf (stderr, "%s(): error, tmp allocation failed, exiting\n", __func__); return NULL; } *lim = newlim; return tmp; } int main (int argc, char **argv) { if (argc < 2) { fprintf (stderr, "Error: insufficient input. Usage: %s input_file\n", argv[0]); return 1; } char *line = NULL; /* forces getline to allocate space for buf */ ssize_t read = 0; /* number of characters read by getline */ size_t n = 0; /* limit number of chars to 'n', 0 no limit */ char **filebuf = NULL; int linecnt = 0; size_t limit = MAXLINES; FILE *ifp = fopen(argv[1],"r"); if (!ifp) { fprintf(stderr, "\nerror: failed to open file: '%s'\n\n", argv[1]); return 1; } filebuf = calloc (MAXLINES, sizeof (*filebuf)); /* allocate MAXLINES pointers */ while ((read = getline (&line, &n, ifp)) != -1) /* read each line in file with getline */ { if (line[read - 1] == 0xa) { line[read - 1] = 0; read--; } /* strip newline */ if (linecnt >= (limit - 1)) /* test if linecnt at limit, reallocate */ { filebuf = recalloc (&limit, filebuf); /* reallocate filebuf to 2X size */ if (!filebuf) { fprintf (stderr, "error: recalloc failed, exiting.\n"); return 1; } } filebuf[linecnt] = strdup (line); /* copy line (strdup allocates) */ linecnt++; /* increment linecnt */ } fclose(ifp); if (line) free (line); /* free memory allocated to line */ linecnt = 0; /* reset linecnt to iterate filebuf */ printf ("\nLines read in filebuf buffer:\n\n"); /* output all lines read */ while (filebuf[linecnt]) { printf (" line[%d]: %s\n", linecnt, filebuf[linecnt]); linecnt++; } printf ("\n"); free_buffer (filebuf); /* free memory allocated to filebuf */ return 0; } 

看看这两个例子。 知道有很多方法可以做到这一点。 这些示例仅提供一种方法,提供使用一些额外技巧的示例,而不是您通常会发现的。 试一试。 如果您需要更多帮助,请发表评论。

我建议你使用mallocrealloc来管理你的记忆。 跟踪数组的大小或它有多少条目,并在数组不够大时调用realloc使其大小加倍。

Op似乎需要将数据存储在某处

 #define N 100000u char BABuffer[N]; int main(int argc, char *argv[]) { size_t lcount = 0; size_t ccount = 0; char words[1024 + 2]; while(fgets(words, sizeof words, stdin) != NULL) { size_t len = strlen(words); if (ccount + len >= N - 1) { fputs("Too much!\n", stderr); break; } memcpy(&BABuffer[ccount], words, len); ccount += len; lcount++; } BABuffer[ccount] = '\0'; printf("Read %zu lines.\n", lcount); printf("Read %zu char.\n", ccount); fputs(BABuffer, stdout); return 0; } 

注意: ccount包括行尾字符。