#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?
答案 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个字符。)