一个more程序的实现

摘要:在linux系统中,我们经常用到more命令来显示文件内容,那么more命令是如何实现的呢?如何在终端反显一个字符串,比如“more”?如何在输入重定向的时候从键盘读入命令?本文通过more命令的实现来讲解相关知识。附录中是本文所使用的代码。


1)和shell程序不同,程序名称本身也是命令行参数的一个,从0开始计算


2)关于设备/dev/tty

/dev/tty文件的存在,有一个特殊的用法:
当标准输入stdin和标准输出stdout被重定向时,我们仍然可以通过/dev/tty文件而实现对键盘的读取和对显示器的输出!


3)fgets函数

函数原型:char *fgets(char *buf, int bufsize, FILE *stream);
参数:
*buf: 字符型指针,指向用来存储所得数据的地址。
bufsize: 整型数据,指明buf指向的字符数组的大小。
*stream: 文件结构体指针,将要读取的文件流。
功能:
从文件结构体指针stream中读取数据,每次读取一行。读取的数据保存在buf指向的字符数组中,每次最多读取bufsize-1个字符(第bufsize个字符赋'\0'),如果文件中的该行,不足bufsize个字符,则读完该行就结束。函数成功将返回buf,失败或读到文件结尾返回NULL。因此我们不能直接通过fgets的返回值来判断函数是否是出错而终止的,应该借助feof函数或者ferror函数来判断

4)fputs函数

函数名: fputs
功 能:向指定的文件写入一个字符串(不自动写入字符串结束标记符‘\0’)。成功写入一个字符串后,文件的位置指针会自动后移,函数返回为一个非负整数;否则返回EOF(符号常量,其值为-1)
用 法: int fputs(char *str, FILE *fp);

5)getc函数

函数名: getc
功 能: 从流中取字符
用 法: int getc(FILE *stream);//read the next character from stream and return it as an unsigned char cast to a int ,or EOF on end of file or error.
注意: 此函数被ISO C声明为一个宏,所以在用时不能将其做为函数指针传(有一些编译器将其以函数形式也给另说)。它的原型如下
#define getc(_stream) (--(_stream)->_cnt >= 0?0xff & *(_stream)->_ptr++ : _fillbuf(_stream))


6)char *arv[] 关于二维数组,指针与指向指针的指针:

注意,申明了指针,这个指针“对应的数组”的存储空间被没有分配

二维数组的本质:

int*p, a[3][4]为例

所有的数组都看作是一维数组,只不过数组元素不同;而为数组的元素是“一行”而不是“一个”。

C语言中,在函数体中或在函数外部定义的一维数组名是一个地址常量,其值为数组第一个元素的地址,此地址的基类型就是数组元素的类型(所以我们在申明二维数组的时候可以省略第一维,但不能省略第二维度,因为要确定数组元素的类型)。

因此,赋值语句p=a[i];是合法的。我们已知a[i]也可以写成:*(a+i),故以上赋值语句也可写成:p=*(a+i);

二维数组名应理解为一个行指针。在表达式a+1中,数值1的单位应是4×2个字节,而不是2个字节。赋值语句p=a;是不合法的,因为pa的基类型不同。再次申明:基类型不同的两个变量之间不能直接赋值,从这个角度说,数组类型不是一个单独的类型而是包含了很多不同的类型。

通过地址来引用二维数组元素若有以下定义:inta[3][4],i,j;且当0≤i30≤j4,则a数组元素可用以下五种表达式来引用:(1a[i][j]2*(a[i]+j)3*(*(a+i)+j)4(*(a+i))[j]5*(&a[0][0]+4*i+j)

二维数组与指针数组:通过建立一个指针数组来引用二维数组元素若有以下定义:int*p[3], a[3][2], i,j;在这里,说明符*p[3]中,也遵照运算符的优先级,一对[]的优先级高于*号,因此p首先与[]结合,构成p[3],说明了p是一个数组名,系统将为它开辟3个连续的存储单元;在它前面的*号则说明了数组p是指针类型,它的每个元素都是基类型为int的指针。若满足条件:0≤i3,p[i]a[i]的基类型相同,p[i]=a[i]是合法的赋值表达式。

二维数组做函数参数:

VoidFunc(int array[3][10]);

voidFunc(int array[][10]);

可以省略一维空间的大小,但是不能第二维,它是3个长度为10的数组,不是10个长度为3的数组;同样可以用int**p来进行



#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#define LINELEN 512
#define PAGELEN 24
void do_more(FILE *fp);
int see_more(FILE *fp);
int main(int arc,char *arv[])
{
  FILE *fp=NULL;
  if(arc==1)
    do_more(stdin);
  else
  {
      fp=fopen(arv[1],"r");
      if(fp==NULL)
      {   
         printf("can't open file %s",*arv);
         exit(0);

      }   
      do_more( fp);
      fclose(fp);
  }
  return 0;
}

void do_more(FILE *fp)
{
  char line[LINELEN];
  FILE *fptty;
  int num_line=0;
  int see_more();
  int reply=0;
  fptty=fopen("/dev/tty","r");
  while (fgets(line,LINELEN,fp))
  {
    if(PAGELEN==num_line)
    {   
      reply=see_more(fptty);
      if(reply==0)
        break;
      num_line-=reply;
    }
    if(fputs(line,stdout ) == EOF )
      exit(1);
    num_line++;
  }
}

int see_more(FILE *cmd)
{
  int c;
printf("\033[7m more?\033[m");
  while( ( c=getc(cmd))!=EOF)
  {
    if(c=='q')
      return 0;
    if(c==' ')
      return PAGELEN;
    if(c=='\n')
      return 1;
    return 0;
  }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值