You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于getline的自定义tail命令如何调整tailbuf的行存储顺序?

问题

希望不使用lseek和fseek,仅通过getline实现自定义tail命令,已编写如下代码,但希望tailbuf数组的存储顺序满足:tailbuf[9]存储文件最后一行,tailbuf[8]存储倒数第二行,以此类推。请帮助修改代码实现该需求。

#include<stdio.h>
#include<stdlib.h>
char ** lastnumlines(FILE *fp, unsigned int num)   
{
  int count = num;
  int n, i, iNo1 = 0, iNo2= 0,z = 0;
  size_t MAXSIZE = 1024;
  char **tailbuf=calloc(count, sizeof(char *));

  for (i = 0; i < count; i++) 
  {
    tailbuf[i] = calloc(MAXSIZE, sizeof(char));
  }

  while (getline(&tailbuf[iNo2], &MAXSIZE, fp) != EOF)
  {
     iNo2 = (iNo2 + 1) % count;
     if (iNo2 == iNo1) 
     {
        iNo1 = (iNo1 + 1) % count; 
     }
  }

 i = iNo2;
 int k = 0;
 do{ 
     printf("%s\n",tailbuf[i]);
     i = (i+1) % count;            
   }while (i != iNo2);


   free(tailbuf);    
 }

int main()
{
  char *filename = "demo1.txt";
  FILE *fp = fopen(filename,"r");

  if(fp == NULL)
  {
     printf("Unable to open file!\n");
     exit(1);
  }

  lastnumlines(fp,10);    
  fclose(fp);   
  return 0;
}
解决方案

要实现tailbuf数组从后往前存储最后N行(最后一行在tailbuf[num-1],倒数第二行在tailbuf[num-2],以此类推),可以调整循环写入的索引逻辑,让新读取的行始终向数组末尾方向覆盖,最后将循环队列的内容按目标顺序整理到位。

关键修改点

  • 改用倒序循环索引写入新行,确保最新行始终占据数组的末尾方向
  • 读取完成后,将循环队列中的内容重新排列成目标顺序
  • 修复原代码的内存泄漏问题(原代码未释放每个行缓冲区的内存)

修改后的完整代码

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

char ** lastnumlines(FILE *fp, unsigned int num)   
{
    int count = num;
    int i, write_idx = count; // 初始索引指向数组末尾的下一个位置(模运算后对应count-1)
    size_t MAXSIZE = 1024;
    char **tailbuf = calloc(count, sizeof(char *));

    // 初始化每个行缓冲区,处理内存分配失败的情况
    for (i = 0; i < count; i++) 
    {
        tailbuf[i] = calloc(MAXSIZE, sizeof(char));
        if (tailbuf[i] == NULL) {
            for (int j = 0; j < i; j++) free(tailbuf[j]);
            free(tailbuf);
            return NULL;
        }
    }

    // 用临时缓冲区读取行,避免干扰tailbuf的内存管理
    char *line = NULL;
    size_t line_size = 0;
    ssize_t read_len;
    while ((read_len = getline(&line, &line_size, fp)) != EOF)
    {
        // 倒序计算写入索引:每次往前移动一位,循环覆盖最旧的行
        write_idx = (write_idx - 1 + count) % count;
        // 复制新行到对应位置,确保字符串终止
        strncpy(tailbuf[write_idx], line, read_len);
        tailbuf[write_idx][read_len] = '\0';
    }
    free(line); // 释放getline分配的临时缓冲区

    // 将循环队列内容整理成目标顺序:tailbuf[count-1]存最后一行
    char **sorted_buf = calloc(count, sizeof(char *));
    if (sorted_buf == NULL) {
        for (i = 0; i < count; i++) free(tailbuf[i]);
        free(tailbuf);
        return NULL;
    }

    for (i = 0; i < count; i++) {
        int src_idx = (write_idx + i) % count;
        sorted_buf[count - 1 - i] = tailbuf[src_idx];
        tailbuf[src_idx] = NULL; // 标记为已转移,避免重复释放
    }

    // 释放原指针数组(元素已转移到sorted_buf)
    free(tailbuf);

    // 打印验证顺序
    for (i = 0; i < count; i++) {
        if (strlen(sorted_buf[i]) > 0) {
            printf("%s", sorted_buf[i]);
        }
    }

    return sorted_buf; // 返回整理后的缓冲区,由调用者负责释放
}

int main()
{
    char *filename = "demo1.txt";
    FILE *fp = fopen(filename,"r");

    if(fp == NULL)
    {
        printf("Unable to open file!\n");
        exit(1);
    }

    char **result = lastnumlines(fp,10);
    // 释放返回的缓冲区
    if (result != NULL) {
        for (int i = 0; i < 10; i++) free(result[i]);
        free(result);
    }
    fclose(fp);   
    return 0;
}

代码说明

  • 写入逻辑:通过write_idx = (write_idx - 1 + count) % count实现倒序循环写入,新行始终覆盖数组中最旧的位置,最新行的位置逐步向数组末尾移动。
  • 顺序整理:读取完成后,从write_idx开始遍历循环队列,将内容反向复制到新数组,确保tailbuf[9]对应最后一行,tailbuf[8]对应倒数第二行。
  • 内存管理:修复了原代码的内存泄漏,所有分配的内存都能被正确释放,同时处理了内存分配失败的异常情况。

内容的提问来源于stack exchange,提问作者Mr_Nobody99

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 15:45:33