2010-01-10 129 views
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函数中,如果指向缓冲区的指针超过了它的最大大小,它将被封装。但我不明白包装/解包功能到底做了什么。有人可以向我解释吗?该方式包装工作,为什么没有这个代码的作家只是返回-1,如果缓冲区溢出?

回答

5

为了演示原则:假设您将10个字符'0'到'9'放入8字节缓冲器,使用相同的方案:

后7个字符:

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

的第八字符之后:

+---+---+---+---+---+---+---+---+ 
| 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行中的某些早期行将丢失)。

+0

@Matthew,好图! – Hogan 2010-01-10 15:22:33

+0

谢谢:),这就解释一下吧! – Tool 2010-01-10 15:26:24

0

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

解包然后放在最后的最古老的东西,所以行看起来从行的开头截断。 (10字符缓冲区中的12个字符行将显示从第3个字符开始的最后10个字符)。