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

时间:2014-10-23 21:18:30

标签: c stdin fgets

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

#include <stdio.h>
#include <string.h>


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)。 如果有人知道解决方案会很棒。提前谢谢。

3 个答案:

答案 0 :(得分:2)

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

答案 1 :(得分:2)

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

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

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

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

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

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

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

在main()

中重新分配的第一个示例
10

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

# include <stdio.h>
# include <stdlib.h>
# include <string.h>

#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;
}

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

答案 2 :(得分:1)

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包含行尾字符。