【问题标题】:Read text from a file and realloc when needed从文件中读取文本并在需要时重新分配
【发布时间】:2012-11-12 15:51:50
【问题描述】:

我想逐行读取文本文件中的文本,并对这些行进行一些处理。我可以做所有的处理,但我不能用 malloc-realloc 增加内存。我首先给了有限的内存,如果我的文本文件的行字符在这个限制内,一切都很好。如果我使用像每行 10,000 个字符这样的大文件,它只会读取到我的限制。我不完全了解如何使用realloc()。我该怎么处理这段代码?

 void stat(char* fileptr)
{

  FILE *fp;
  char *linebuffer;
  int line=0;
  int sum=0;
  int max=0;
  int min=0;
  int maxlinelen=512;
  int i=0,j=0;
  int maxlen=512;
  int curlinelen[maxlen];

  linebuffer=(char*) malloc(maxlinelen * sizeof(char));
  if(linebuffer==NULL)
    {
      printf("Error occurred allocating memory for linebuffer");
      exit(1);
    }


  if((fp=fopen(fileptr,"r"))!=NULL)
  {
    while((fgets(linebuffer,maxlinelen,fp))!=NULL)
      {
    if(strlen(linebuffer)==maxlinelen)
      {
        maxlinelen*=2;
        linebuffer=realloc(linebuffer,maxlinelen * sizeof(char));
        if(linebuffer==NULL)
          {
        printf("Error occurred reallocating space for linebuffer");
        exit(1);
          }
      }
    line++;

        sum=sum+strlen(linebuffer);
    curlinelen[i]=strlen(linebuffer);
    i++;

      }
  }
  min=curlinelen[0];
  max=curlinelen[0];
  for(j=0;j<line;j++)
    {
      if(curlinelen[j]<min)
    {
      min=curlinelen[j];
    }
      if(curlinelen[j]>max)
    {
      max=curlinelen[j];
    }
    }


 printf("No. of lines        =%d\n",line);
 printf("Maximum line length =%d\n",max);
 printf("Minimum line length =%d\n",min);       
 printf("Average line length =%8.2f\n",(float)sum/(float)line);

 fclose(fp);
}

【问题讨论】:

  • * sizeof(char) 是不需要的,对malloc() 的返回进行类型转换是不明智的。
  • 我会使用sizeof(*linebuffer) 而不是sizeof(*linebuffer),如果您决定将行缓冲区的类型更改为宽字符串或其他内容,它会自动变大。

标签: c


【解决方案1】:
fgets(linebuffer,maxlinelen,fp)

linebuffer 中最多读取和存储maxlinelen - 1 字符,并以0 终止它。因此

if(strlen(linebuffer)==maxlinelen)

永远不会满足,strlen(linebuffer) 最多可以是maxlinelen - 1。更改条件,如果文件包含长行,您将看到maxlinelen 增加(除非realloc 失败)。

但是,您当前的代码会将读入的部分行计为整行,然后将该行的下一个块读取为新行。要增加缓冲区直到整行适合,您必须在收集行长度和增加行数之前继续从文件中读取。但是我们必须检查是否读取了整行(包括末尾的换行符),以防fgets 在扩大缓冲区之前读取chars 的最大允许数量,或者我们将连接以下行并计数两个(或者在怪异的情况下甚至更多)行作为一个。

while((fgets(linebuffer,maxlinelen,fp))!=NULL)
  {
  while((strlen(linebuffer) == maxlinelen-1) && (linebuffer[maxlinelen-2] != '\n'))
  {
    maxlinelen*=2;
    linebuffer=realloc(linebuffer,maxlinelen * sizeof(char));
    if(linebuffer==NULL)
    {
        printf("Error occurred reallocating space for linebuffer");
        exit(1);
    }
    fgets(linebuffer + (maxlinelen/2 - 1), maxlinelen/2 + 1, fp);
  }

这样做会是一种(相当低效,由于strlen 调用)的方式。

【讨论】:

  • 您可以做更多的编码工作,并通过使用fgetc 避免在可能较大的字符串上重复使用strlen。不过,我不会挑剔它,因为那不好玩。
  • 谢谢丹尼尔!!但我仍然有问题。我的示例文本文件(infile)就是这样;它的正确输出;行数:2 最大行长度:50001 最小行长度:10001 平均:30001.00 我的编输出行数:8 最大行长度:25427 最小行长度:511 平均:7500,25 我不明白。有什么问题吗?
  • @ccc 那是因为你增加了行数line++; 等,即使fgets 没有读入整行。打印出 curlinelen 数组,直到它被填满为止。
  • @DanielFischer 这个文件变成 2 行。第一行变成 10001 a,第二行变成 50001 b。但我的编读 8 行??我在这里感到困惑。我尝试了打印输出 curlinelen 数组,我得到了 seg.fault。像那样,............ line++; sum=sum+strlen(linebuffer); curlinelen[i]=strlen(linebuffer); printf("%s\n",curlinelen[i]); //我也试过 %c 我明白了吗? ? ?有些人认为 i++;
  • @ccc 首先,它从第一行读取 511 'a's,然后重新分配并增加行数,将 511 存储在 curlinelen[0] 中。然后它从第一行读取下一个 1023 'a's,将其作为第二行并增加缓冲区。然后下一个 2047 'a's,仍然从文件的第一行作为第 3 行,等等。
猜你喜欢
  • 1970-01-01
  • 2013-08-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-05-04
  • 2018-09-18
  • 2016-08-25
相关资源
最近更新 更多