第五章 标准I/O库

第五章   标准I/O

 

       这一章也没什么内容,就几个函数。关于流是个什么东西我也搞不懂,应该是一个数据结构的实现吧,学了第16章会接触到一个大点儿的数据结构用来表示数据库信息,觉得它和流差不多,都是返回一个用于对数据结构操作的指针。流不是咱们写的,也不必深究,知道用FILE来操作流就行了。FILE就像一个游戏机手柄,有了手柄你就可以尽情的玩游戏了。

 

       标准I/O是使用缓存的,最难的一点儿就是理解缓存的刷新机制,如果掌握不了,你写的程序很可能达不到你想要的效果。

 

概念:

 

标准输入stdin

 

标准输出stdout

 

标准出错srderr

 

我老是将这三个标准和STDIN_FILENO,STDOUT_FILENO,STDERR_FILENO相混淆。老是等到编译程序说这个没定义啦,那个没定义啦我才改过来。既然要些笔记,就想个办法区分他们。文件描述符是一个可用的最小整数。而STDIN_FILENO是一个宏定义,它就是一个常数啦。对流进行操作的是一个FILE指针,stdin等不是宏,是一个指针变量

 

 

 

缓存

 

标准I/O缓存的目的是尽可能减少使用readwrite调用的数量。在某些情况下,这是非常可怕的。缓存就像两头有个个水龙头的水池,一个进水,一个排水。为了尽可能节省人力,只有进水管将水池灌满才有人去打开那个排水管。在现面等水的人很可能会因为这段时间而渴死哦。当然,水池也有大有小。

 

全缓存:

 

行缓存:遇新行符刷新

 

无缓存:

 

刷新:在本章的意思是将缓存中的内容写到磁盘上(想不想打开排水管啊^_^

 

 

 

ANSIC要求下列缓存特点:

 

1)只有标准输入和标准输入并不涉及交互作用设备时,他们才是全缓存的。

 

2)标准出错决不会是全缓存的。

 

 

 

                            输入                                                输出

 

字符    getc,fgetc,getchar                      putc,fputc,putchar

 

 

 

          fgets,gets                                          fputs,puts

 

 

 

                 fread                                                fwrite

 

 

 

格式化  printf,fprintf,sprintf              scanf,fscanf,sscanf

 

         vprintf,vfprintf,vsprintf

 

 

 

 

 

函数运用:

 

----------------证明缓存的存在-------------------------

 

//----------------file1.c-------------------------

 

#include <stdio.h>

 

main()

 

{

 

       printf("Hello world!");

 

       sleep(5); //先睡眠5秒在退出

 

}

 

 

 

//---------------file2.c-------------------------

 

#include <stdio.h>

 

main()

 

{

 

       printf("Hello world!/n");

 

       sleep(5);

 

}

 

这两个程序只有一处不同,即'/n'新行符。file2.cprintf'/n'就立即刷新了,而file1.c在结束是才刷新的(有exit刷新,后面章节有介绍)。这种危机在标准I/O中处处存在,可要想好哦。

 

 

 

 

 

 

 

fopen      打开一指定文件

 

freopen   打开一指定文件并替换一指定流

 

fdopen    打开一文件描述符指定的文件

 

fclose     关闭一指定流

 

//------------------freopen.c----------------------

 

#include <stdio.h>

 

main()

 

{

 

       creat("abc",0600);

 

       freopen("abc","r+",stdout);//这里不会出现可执行x,注意啦r+""

 

       printf("Hello world!/n");

 

       fclose(stdout);

 

}

 

//---------------------end-----------------------

 

king@king-laptop:~/blog$ gcc -o freopen freopen.c

 

king@king-laptop:~/blog$ ./freopen

 

king@king-laptop:~/blog$ cat abc    //看到了吗,我们把printf变成了fprintf

 

Hello world!

 

king@king-laptop:~/blog$

 

 

 

 

 

getc,fgetc,getchar

 

getchar等同于getc(stdin)

 

getc可以实现为宏,而fgetc一定是个函数,允许将fgetc的地址作为一个参数传递(我不懂唉)

 

//------------典型错误---------------

 

//-----------getchar.c-------------

 

#include <stdio.h>

 

main()

 

{

 

       char c;

 

       while((c=getchar())!=EOF)

 

              putchar(c);

 

       printf("saft exit/n");

 

}

 

//-----------end----------------

 

看着挺不错,其实是个死循环

 

# define EOF (-1)

 

在我的系统里永远出现不了等于-1的字符

 

 

 

 

 

ferror      检测出错

 

feod       检测到达文件尾部

 

clearerr 清除文件表示

 

读字符的三个函数的出错返回与到达文件尾端的是EOF,那怎么区分的?

 

//----------------ferror.c-------------------

 

#include <stdio.h>

 

main()

 

{

 

       FILE *fp;

 

       char ch;

 

 

 

       fp=fopen("abc","r");

 

       while((ch=fgetc(fp))!=EOF)

 

              printf("%c",ch);

 

 

 

       if(ferror(fp))

 

              printf("/nerror/n");//读取错误啦

 

       if(feof(fp))

 

              printf("/nfile end/n");//到文件尾部啦

 

       clearerr(fp);

 

}

 

//-----------------------end-----------------

 

king@king-laptop:~/blog$ gcc -o ferror ferror.c

 

king@king-laptop:~/blog$ ./ferror

 

Hello world!

 

 

 

file end

 

king@king-laptop:~/blog$

 

 

 

 

 

ungetc

 

将字符回送流中,再次读取时的顺序与送回的顺序相反

 

回送的字符不一定是上次读到的字符

 

模拟机制:定义一个栈,调用ungetc就把字符压入栈,再取字符时就从栈中取,直到指针到达栈底。

 

也不知怎么了,我用不了这个函数,也许不支持,就不写例子了#include <stdio.h>

 

#include <sys/stat.h>

 

main()

 

{

 

       int fd;

 

       FILE *fp;

 

       char *p="1234567890";

 

       fd=creat("1234",0600);

 

       write(fd,p,10);

 

 

 

       fp=fopen("1234","r+");

 

       getc(fp);

 

       getc(fp);

 

       printf("file local is %ld/n",ftell(fp));

 

 

 

       fseek(fp,4,SEEK_CUR);

 

 

 

       printf("after fseek get %c/n",getc(fp));

 

       rewind(fp);

 

       printf("file local is %ld after rewind/n",ftell(fp));

 

       fclose(fp);

 

}

 

 

 

 

 

putc,fputc,putchargetc,fgetc,getchar是一样的,只是方向不同,就不举例啦。

 

 

 

 

 

fgets

 

gets==fgets(stdin)

 

gets从标准输入读,但不推荐使用。问题是调用者在使用gets时不能指定缓存的长

 

度。这样就可能造成缓存越界,1988年的因特网蠕虫事件曾利用此缺陷。

 

-------------测试一下gets的破坏力-------------------

 

//--------------gets.c-----------------------

 

#include <stdio.h>

 

main()

 

{

 

       char *p,*q;

 

       p=(char *)malloc(10);

 

       q=(char *)malloc(5);

 

 

 

       gets(q);

 

       printf("q=%s/n",q);//先写要被覆盖的数据

 

 

 

       gets(p);

 

       printf("p=%s/n",p);

 

       printf("q=%s/n",q);//再次查看一下数据有没有被覆盖

 

}

 

//---------------------end-----------------------

 

king@king-laptop:~/blog$ gcc -o gets gets.c          //有警告,不管他,咱干咱的

 

gets.c: 在函数‘main’中:

 

gets.c:5: 警告: 内建函数 ‘malloc’ 不兼容的隐式声明

 

/tmp/ccsIwCLW.o: In function `main':

 

gets.c:(.text+0x36): warning: the `gets'

 

function is dangerous and should not be used.

 

 

 

king@king-laptop:~/blog$ ./gets

 

123456

 

q=123456                   //现在一切正常

 

abcdef

 

p=abcdef

 

q=123456

 

king@king-laptop:~/blog$ ./gets

 

123456

 

q=123456

 

abcdefghijklmnoporst

 

p=abcdefghijklmnoporst

 

q=orst                         //数据被覆盖掉了,gets真是可怕,如果按住一个键半天不撒手????????????

 

king@king-laptop:~/blog$

 

 

 

fput,puts也不说了,puts不像gets那么可怕,不过也不推荐使用

 

 

 

fread,fwrite

 

/写块(二进制),不论是整个文件也好,一个数据结构也好,一个结构数组也好,这都可以。

 

//---------------fwrite.c------------------------

 

#include <stdio.h>

 

#include "ourhdr.h"

 

#include "err_error.h"

 

main()

 

{

 

       FILE *fp;

 

       char a[]={'a','b','c','d','e','f','j'};

 

 

 

       if(creat("cba",0600)==-1)

 

              err_sys("creat error");

 

 

 

       if((fp=fopen("cba","r+"))==NULL)

 

              err_sys("fopen error");

 

 

 

       if(fwrite(&a,sizeof(char),3,fp)!=3) //记住:并不是复制3次同样的块,而是一个连续的空间

 

              err_sys("fwrite error");

 

}

 

//------------------------end---------------------------

 

king@king-laptop:~/blog$ gcc -o fwrite fwrite.c

 

king@king-laptop:~/blog$ ./fwrite

 

king@king-laptop:~/blog$ cat cba

 

abcking@king-laptop:~/blog$          //原来不是三个a啊,我以为是三个a

 

 

 

 

 

 

 

ftell,fseek,rewind

 

//-------------------ftell.c---------------------

 

#include <stdio.h>

 

#include <sys/stat.h>

 

main()

 

{

 

       int fd;

 

       FILE *fp;

 

       char *p="1234567890";

 

       fd=creat("1234",0600);

 

       write(fd,p,10);

 

 

 

       fp=fopen("1234","r+");

 

       getc(fp);

 

       getc(fp);

 

       printf("file local is %ld/n",ftell(fp));

 

 

 

       fseek(fp,4,SEEK_CUR);

 

 

 

       printf("after fseek getc is %c/n",getc(fp));

 

       rewind(fp);

 

       printf("file local is %ld after rewind/n",ftell(fp));

 

       fclose(fp);

 

}

 

//---------------------end----------------------

 

king@king-laptop:~/blog$ gcc -o ftell ftell.c

 

king@king-laptop:~/blog$ ./ftell

 

file local is 2

 

after fseek getc is 7

 

file local is 0 after rewind

 

king@king-laptop:~/blog$

 

1234567890指针到了哪儿,自己数

 

 

 

 

 

fileno 看看程序就知啥意思,小吧

 

//-------------fileno.c----------------

 

#include <stdio.h>

 

main()

 

{

 

       printf("STDOUT_FILENO is %d/n",fileno(stdout));

 

}

 

//----------------end-----------------

 

king@king-laptop:~/blog$ gcc -o fileno fileno.c

 

king@king-laptop:~/blog$ ./fileno

 

STDOUT_FILENO is 1

 

king@king-laptop:~/blog$

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值