打印最后一行输入

时间:2010-01-10 14:38:07

标签: c function string lines

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

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

在readlines函数中,如果指向缓冲区的指针超过其最大大小,则会被包装。但我不明白包装/解包功能究竟做了什么。有人可以向我解释一下吗?包装的工作原理以及为什么如果缓冲区溢出,这段代码的编写器只返回-1?

2 个答案:

答案 0 :(得分: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行中较早的一些将会丢失。)

答案 1 :(得分:0)

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

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