编写程序 tail,打印输入的最后 n 行。
大家好,我关于其实现程序不清楚的部分是如下程序段,书中对i = (i + 1) % LINES的描述是这样的。
for (i = first; n-- > 0; i = (i + 1) % LINES)
printf("%s", lineptr[i]);
书中对于该段语句的解读:
因为i从初值first开始递增n次,那么,当i大于LINES时,就会出现某些输人行被反复打印多次的情况。为了避免出现这一局面,我们使用了取模运算符(%)来确保i的取值范围能够落在0到LINES- 1之间。
我知道i = (i + 1) % LINES所起到地作用就是限制变量i的范围。但在思考之后发现这并没什么意义?原因如下:
i的初始值为first,如果最终i要大于LINES,那么first+n就要大于LINES。
又因为程序段中
first = last - n;//输出行的起始索引,要从输入最后一行的索引开始,退回n个值
那么就是说要满足上面所述的这种情况,last就要大于LINES,但是last不可能大于LINES呀!
原因如下:
if (++last >= LINES)
last = 0;//如果输入行总数(last的值)每超过LINES一次,last值就重置一次(设置为0),类似环状结构
所以我就很好奇i = (i + 1) % LINES的重要性
产生的问题:
我无法理解刚才书中这段话的意思。
1.什么时候才会出现它所说的某些输入行被反复打印
2.它说的会出现某些输人行被反复打印多次的情况,某些行是指这些行是随机的吗?
3.我直接把这个程序段
for (i = first; n-- > 0; i = (i + 1) % LINES)
printf("%s", lineptr[i]);
改成这个可以吗,因为根据我上面的分析变量i是不可能大于LINES的,所以我觉得没必要限制范围。
for (i = first; n-- > 0; i ++)
printf("%s", lineptr[i]);
实现程序
/* Write a Program tail, which prints the last n lines of its input. By default n is 10. let us say; but it can be changed
by an optional argument so that tail -n */
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define DEFLINES 10 /* default # of lines to print */
#define LINES 3 /* maximum # of lines to print */
#define MAXLEN 100 /* maximum length of an input line */
void error(char *);
int mgetline(char *, int);
/* print the last n lines of the input */
int main(int argc, char *argv[])
{
char *p;
char *buf; /* pointer to the large buffer */
char *bufend; /* end of the large buffer */
char line[MAXLEN];
char *lineptr[LINES]; /* pointer to lines read */
int first, i, last, len, n, nlines;
scanf("%d", &argc);
for (int i = 1; i < argc; i++)
{
argv[i] = (char *)malloc(MAXLEN * sizeof(char));
scanf("%s", argv[i]);
}
getchar();
if (argc == 1)
n = DEFLINES;
else if (argc == 2 && (*++argv)[0] == '-')
n = atoi(argv[0] + 1);
else
error("Usage: tail [-n]");
if (n < 1 || n > LINES)//将输入的最后n行打印出来,所以n的值有意义的同时,不能够大于最多允许打印的行数
n = LINES;
for (i = 0; i < LINES; i++)
lineptr[i] = NULL;
if ((p = buf = malloc(LINES * MAXLEN)) == NULL)
error("tail: cannot allocate buf");
bufend = buf + LINES + MAXLEN;
last = 0; //上一个输入行的索引
nlines = 0; //输入行的个数
while ((len = mgetline(line, MAXLEN)) > 0)
{
if (p + len + 1 >= bufend)
p = buf;
lineptr[last] = p;
strcpy(lineptr[last], line);
if (++last >= LINES)
last = 0;
p += len + 1; //mgetline返回的字符串长度len没有将终止符'\0'算在其中
nlines++;
}
if (n > nlines) //lines of request more than recording ?
n = nlines;
first = last - n;//输出行的起始索引,要从输入最后一行的索引开始,退回n个值
if (first < 0)
first += LINES;
for (i = first; n-- > 0; i = (i + 1) % LINES)
printf("%s", lineptr[i]);
return 0;
}
/* error: print error messages and exit */
void error(char *s)
{
printf("%s\n", s);
exit(1);
}
/* mgetline: read a line into s and return length */
int mgetline(char *s, int lim)
{
int c, i;
for (i = 0; i < lim - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
s[i] = c;
if (c == '\n')
{
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}