2
#include <stdio.h>

#define MAXLINES    5000    /* Maximum number of lines to display. */

char *lineptr[MAXLINES];    /* Pointer to input lines. */

#define BUFFERSIZE 1000

#define DEFAULT_LAST 10

int readlines(char *lineptr[], char *buffer, int maxlines);
static void unwrap(char *buffer, int index);
static void reverse(char *lineptr[], int nlines);

main(int argc, char *argv[])
{
    int nlines, i, last, offset;
    char buffer[BUFFERSIZE];
    char *p;

    last = DEFAULT_LAST;
    for (i = 0; i < argc; i++) {
        p = argv[i];
        if (*p++ == '-') {
            last = 0;
            while (isdigit(*p)) {
                last = last * 10 + *p - '0';
                p++;
            }
            if (*p != '\0') {
                printf("invalid argument: %s\n", argv[i]);
                last = DEFAULT_LAST;
            }
        }
    }

    nlines = readlines(lineptr, buffer, MAXLINES);
    if (nlines < 0) {
        printf("error: input too big to process\n");
        return 1;
    }
    if (nlines < last) {
        printf("error: only printing the last %d lines.\n", nlines);
        offset = 0;
    } else if (last > MAXLINES) {
        offset = nlines - MAXLINES;
    } else {
        offset = nlines - last;
    }
    for (i = 0; i < nlines && i < last; i++)
        printf("%s\n", lineptr[offset + i]);

    return 0;
}

int readlines(char *lineptr[], char *buffer, int maxlines)
{
    int c, nlines;
    int wrapped;
    char *p;

    /* The input lines are stored end-to-end in the buffer, with
       newlines converted to null bytes. */
    wrapped = 0;
    p = buffer;
    while ((c = getchar()) != EOF) {
        if (c == '\n')
            *p = '\0';
        else
            *p = c;
        p++;
        if (p >= buffer + BUFFERSIZE) {
            p = buffer;
            wrapped = 1;
        }
    }
    /* Rearrange the buffer so the oldest byte comes first. */
    if (wrapped) {
        unwrap(buffer, p - buffer);
        p = buffer + BUFFERSIZE;
    }
    p--;
    *p = '\0';
    nlines = 0;
    while (p >= buffer && nlines < maxlines) {
        p--;
        if (*p == '\0')
            lineptr[nlines++] = p + 1;
    }
    reverse(lineptr, nlines);

    return nlines;
}

static void unwrap(char *buffer, int index)
{
    char work[BUFFERSIZE];

    memmove(work, buffer + index, BUFFERSIZE - index);
    memmove(work + BUFFERSIZE - index, buffer, index);
    memmove(buffer, work, BUFFERSIZE);

    return;
}

static void reverse(char *lineptr[], int nlines)
{
    char *tmp;
    int i;

    for (i = 0; i < nlines / 2; i++) {
        tmp = lineptr[i];
        lineptr[i] = lineptr[nlines - i - 1];
        lineptr[nlines - i - 1] = tmp;
    }
return;
}

该程序打印最后 -n 行输入,将行存储到指针数组中。

在 readlines 函数中,如果指向缓冲区的指针超过了它的最大大小,它就会被包装。但我不明白包装/展开功能究竟做了什么。有人可以向我解释吗?wrap 的工作方式,如果缓冲区溢出,为什么这段代码的编写者不返回-1?

4

2 回答 2

5

演示原理:假设您使用相同的方案将 10 个字符('0' 到 '9')放入 8 字节缓冲区:

7个字符后:

+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 |   |
+---+---+---+---+---+---+---+---+
  ^                           ^
buffer                        p

第 8 个字符之后:

+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+---+---+---+---+---+---+---+---+
  ^                               ^
buffer                            p

所以现在p被重置并wrapped设置为1:

+---+---+---+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+---+---+---+---+---+---+---+---+
  ^
buffer
  p

第 10 个字符之后:

+---+---+---+---+---+---+---+---+
| 8 | 9 | 2 | 3 | 4 | 5 | 6 | 7 |
+---+---+---+---+---+---+---+---+
  ^       ^
buffer    p

现在unwrap()代码重新排列缓冲区,如下所示:

+---+---+---+---+---+---+---+---+
| 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
+---+---+---+---+---+---+---+---+
  ^                               ^
buffer                            p

程序正在这样做(而不是仅仅放弃),因此即使文件比缓冲区大得多,它仍然可以工作。(除非最后 10 行的总长度大于缓冲区,在这种情况下,最后 10 行中较早的部分将丢失)。

于 2010-01-10T15:15:25.597 回答
0

该程序将所有行读入行数组。数组中的每个元素都有固定的大小。如果一行长于一行的最大大小,它会“包装”它并在缓冲区的开头重新开始填充缓冲区。

Unwrap 然后将最旧的东西放在最后,因此该行看起来从行的开头截断。(10 个字符的缓冲区中的 12 个字符的行将显示从第 3 个字符开始的最后 10 个字符。)

于 2010-01-10T15:04:35.810 回答