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

K&R习题5-13:如何实现符合内存要求的无限行输入tail程序

K&R习题5-13实现疑问

习题5-13:编写tail程序,打印输入的最后n行。默认n为10,可通过可选参数修改,例如tail -n会打印最后n行。无论输入或n值多么不合理,程序都应合理运行。编写程序时要充分利用可用存储空间;行的存储方式需与5.6节的排序程序相同,不能使用固定大小的二维数组。

这是我目前编写的代码:

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

int isint(char s[]);
int toint(char s[]);
int readlines(char *lineptr[], int no);
void writelines(char *lineptr[], int no);

#define MAXLINE 100

int main(int argc, char *argv[])
{
    int n = 10, nlines;
    char *lineptr[MAXLINE];

    while (--argc > 0) {
        if ((*++argv)[0] == '-' && isint(*argv) && toint(*argv) <= MAXLINE) {
            n = toint(*argv);
            break;
        }
        else
            printf("invalid argument %s\n", *argv);
    }

    printf("Printing %d line%s\n", n, n > 1 ? "s" : "");
    if ((nlines = readlines(lineptr, n)) >= 0) {
        writelines(lineptr, nlines);
        return 0;
    }
    else {
        printf("input too big too handle\n");
        return 1;
    }

    return 0;
}

int isint(char s[])
{
    while (*s == '-' || *s == '0')
        s++;
    if (isdigit(*s)) {
        while (*s != '\0')
            if (!isdigit(*s++))
                return 0;
        return 1;
    }
    else
        return 0;
}

int toint(char s[])
{
    while (*s == '-' || *s == '0')
        s++;
    return atoi(s);
}

#define MAXLEN 1000

int readlines(char *lineptr[], int no)
{
    char *alloc(int n, int no);
    int get_line(char *, int);
    void push(char *lineptr[], char *p, int len);

    int nlines, len, i;
    char *p, line[MAXLEN];

    for (i = 0; i < no; i++)
        lineptr[i] = NULL;

    nlines = 0;
    while ((len = get_line(line, MAXLEN)) > 0)
        if ((p = alloc(len, no)) == NULL) {
            return -1;
        } else {
            line[len-1] = '\0';
            strcpy(p, line);
            push(lineptr, p, no);
            nlines++;
        }
    return no < nlines ? no : nlines;
}

void writelines(char *lineptr[], int no)
{
    int i;
    
    for (i = 0; i < no; i++)
        if (lineptr[i] != NULL)
            printf("%s\n", lineptr[i]);
}

int get_line(char *line, int lim)
{
    int i, c;

    i = 0;
    while (--lim > 0 && (c = getchar()) != EOF && c != '\n')
        line[i++] = c;
    if (c == '\n')
        line[i++] = c;
    line[i] = '\0';

    return i;
}

void push(char *lineptr[], char *p, int no)
{
    void shift(int i)
    {
        if (i > 1)
            shift(i-1);
        lineptr[i-1] = lineptr[i];
    }

    shift(no-1);
    lineptr[no-1] = p;
}

static char allocbuf[MAXLINE][MAXLEN];
static int allocn = 0;

char *alloc(int n, int no)
{
    if (n < MAXLEN) {
        allocn++;
        return allocbuf[allocn%no];
    } else
        return NULL;
}

该代码可以处理无限行输入,但使用了二维数组,而书籍要求采用如下方式存储行:

#define ALLOCSIZE 10000

static char allocbuf[ALLOCSIZE];
static char *allocp = allocbuf;

char *alloc(int n)
{
    if (n <= ALLOCSIZE - (allocp - allocbuf)) {
        allocp += n;
        return allocp - n;
    } else
        return NULL;
}

void afree(char *p)
{
    if (p >= allocbuf && p < allocbuf + ALLOCSIZE)
        allocp = p;
}

这种方式下我无法用新行替换已存储的过时行。我可以将allocbuf拆分为多个1000字符长的段作为解决方案,但这本质上是手动实现二维数组,属于重复造轮子,不符合书籍要求。我只能想到几种设计方案,但实现难度都很大。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 16:43:13