問題
命令tail用來打印一個文件的最後n行。其格式爲:
tail [-n] filename
其中:
-n :n表示需要打印的行數,省略時n的值爲10。
filename :給定文件名。
如,命令tail –20 example.txt 表示打印文件example.txt的最後20行。
實現該程序,該程序應具有一定的錯誤處理能力,如能處理非法命令參數和非法文件名。
算法分析
1、如何得到需要打印的行數和文件名?
使用命令行參數
int main(int argc, char *argv[])
行數 n = atoi(argv[1]+1)
文件名爲 argv[2]
2、如何得到最後n行?
方法一:使用n個節點的循環鏈表。
首先創建一個空的循環鏈表;
然後再依次讀入文件的每一行掛在鏈表上,最後鏈表上即爲最後n行。
方法二:使用一個n個元素的指針數組。
依次讀入每一行,然後循環掛到指針數組上。
char *lineptr[N]; /存入所讀入的行/
char *line; /當前讀入行/
int i; /讀入的行數/
lineptr[i % n] = (char *)malloc(strlen(line)+1);
strcpy(lineptr[i%n], line);
方法三:兩次掃描文件。
第一遍掃描文件,用於統計文件的總行數N;
第二遍掃描文件時,首先跳過前面N-n行,只讀取最後n行。
如何開始第二遍掃描?
fseek(fp, 0, SEEK_SET);
算法實現(循環鏈表)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DEFLINES 10
#define MAXLEN 81
struct Tail {
char *line;
struct Tail *next;
};
int main(int argc, char *argv[ ])
{
char curline[MAXLEN],*filename;
int n = DEFLINES, i;
struct Tail *first, *ptr;
FILE *fp;
if( argc == 3 && argv[1][0] == '-') {
n = atoi(argv[1]+1); //C 庫函數 int atoi(const char *str) 把參數 str 所指向的字符串轉換爲一個整數(類型爲 int 型)。stdlib.h中聲明
filename = argv[2];
}
else if( argc == 2)
filename = argv[1];
else {
fprintf(stderr, "Usage: tail [-n] filename\n");
return (1);
}
if((fp = fopen(filename, "r")) == NULL){
fprintf(stderr, " Cann't open file: %s !\n", filename);
return (-1);
}
first = ptr = (struct Tail *)malloc(sizeof ( struct Tail));
first->line = NULL;
for(i=1; i<n; i++){
ptr->next = (struct Tail *)malloc(sizeof ( struct Tail));
ptr = ptr->next;
ptr->line = NULL;
}
ptr->next = first;
ptr = first;
while(fgets(curline, MAXLEN, fp) != NULL){
if(ptr->line != NULL)
free(ptr->line);
ptr->line = (char *) malloc ( strlen(curline)+1);
strcpy(ptr->line, curline);
ptr = ptr->next;
}
for(i=0; i<n; i++) {
if(ptr->line != NULL)
printf("%s",ptr->line);
ptr = ptr->next;
}
fclose(fp);
return 0;
}