Chinaunix首页 | 论坛 | 博客
  • 博客访问: 639295
  • 博文数量: 171
  • 博客积分: 2246
  • 博客等级: 大尉
  • 技术积分: 1574
  • 用 户 组: 普通用户
  • 注册时间: 2012-05-31 11:45
文章分类

全部博文(171)

文章存档

2018年(3)

2017年(4)

2015年(1)

2014年(20)

2013年(57)

2012年(86)

分类: LINUX

2013-10-10 18:41:28

以字符串为单位的I/O函数

fgets 从指定的文件中读一行字符到调用者提供的缓冲区中,gets从标准输入读一行字符到调用者提供的缓冲区中。

  1. #include <stdio.h>
  2. char *fgets(char *s, int size, FILE *stream);
  3. char *gets(char *s);
返回值: 成功时s指向哪返回的指针就指向哪,出错或者读到文件末尾时返回NULL。


gets函数无需解释,Man Page的BUGS部分已经说得很清楚了:Never use gets()。gets函数的存在只是为了兼容以前的程序,我们写的代码都不应该调用这个函数。gets函数的接口设计得很有问题,就像strcpy一样,用户提供一个缓冲区,却不能指定缓冲区的大小,很可能导致缓冲区溢出错误,这个函数比strcpy更加危险,strcpy的输入和输出都来自程序内部,只要程序员小心一点就可以避免出问题,而gets读取的输入直接来自程序外部,用户可能通过标准输入提供任意长的字符串,程序员无法避免gets函数导致的缓冲区溢出错误,所以唯一的办法就是不要用它。

现在说说fgets函数,参数s是缓冲区的首地址,size是缓冲区的长度,该函数从stream所指的文件中读取以'/n'结尾的一行(包括'/n'在内)存到缓冲区s中,并且在该行末尾添加一个'/0'组成完整的字符串。(xxx/n/0

如果文件中的一行太长,fgets从文件中读了size-1个字符还没有读到'/n',就把已经读到的size-1个字符和一个'/0'字符存入缓冲区,文件中剩下的半行可以在下次调用fgets时继续读。(xxx/0) + (xxx/n/0)

如果一次fgets调用在读入若干个字符后到达文件末尾,则将已读到的字符串加上'/0'存入缓冲区并返回,如果再次调用fgets则返回NULL,可以据此判断是否读到文件末尾。

注意对于fgets来说,'/n'是一个特别的字符,而'/0'并无任何特别之处,如果读到'/0'就当作普通字符读入。如果文件中存在'/0'字符(或者说0x00字节),调用fgets之后就无法判断缓冲区中的'/0'究竟是从文件读上来的字符还是由fgets自动添加的结束符,所以fgets只适合读文本文件而不适合读二进制文件,并且文本文件中的所有字符都应该是可见字符,不能有'/0'

fputs向指定的文件写入一个字符串,puts向标准输出写入一个字符串。
#include
int fputs(const char *s, FILE *stream);
int puts(const char *s);
返回值:成功返回一个非负整数,出错返回EOF

缓冲区s中保存的是以'/0'结尾的字符串,fputs将该字符串写入文件stream,但并不写入结尾的'/0'。与fgets不同的是,fputs并不关心的字符串中的'/n'字符,字符串中可以有'/n'也可以没有'/n'puts将字符串s写到标准输出(不包括结尾的'/0'),然后自动写一个'/n'到标准输出。



一.char *fgets(char *buf, int bufsize, FILE *stream)


函数 (ISO C)

函数原型:char *fgets(char *buf, int bufsize, FILE *stream);
参数:
  *buf       :字符型指针,指向用来存储所得数据的地址。
  bufsize  : 整型数据,指明buf指向的字符数组的大小。
  *stream : 文件结构体指针,将要读取的文件流。
功能:
       从文件结构体指针stream中读取数据,每次读取一行。读取的数据保存在buf指向的字符数组中,每次最多读取 bufsize-1个字符(第bufsize个字符赋'\0'),如果文件中的该行,不足bufsize个字符,则读完该行就结束。函数成功将返回 buf,失败或读到文件结尾返回NULL。因此我们不能直接通过fgets的返回值来判断函数是否是出错而终止的,应该借助feof函数或者ferror 函数来判断。
注意:《UNIX 环境高级编程》中指出,每次调用fgets函数会造成标准输出设备自动刷清!案例详见《UNIX环境高级编程(第二版)》中程序清单1-5和课后习题5.7,习题5.7的答案中给出了相关的论述。
stream文件流指针体指向文件内容地址的偏移原则
如果使用fgets()读取某个文件,第一次读取的bufsize为5,而文件的第一行有10个字符(算上 '\n'),那么读取文件的指针会偏移至当前读取完的这个字符之后的位置。也就是第二次再用fgets()读取文件的时候,则会继续读取其后的字符。而, 如果使用fgets() 读取文件的时候bufsize大于该行的字符总数加2(多出来的两个,一个保存文件本身的'\n'换行,一个保存字符串本身的结束标识'\0'),文件并不会继续读下去,仅仅只是这一行读取完,随后指向文件的指针会自动偏移至下一行。
例:
如果一个文件的当前位置的文本如下
Love, I Have
Since you can do it.
如果用fgets(str1,6,file1);去读取
则执行后str1 = "Love," ,读取了6-1=5个
这个时候再执行fgets(str1,20,file1)则执行后str1 = " I Have\n"
而如果
fgets(str1,23,file1);
则执行str1="Love ,I Have",读取了一行(包括行尾的'\n',并自动加上字符串结束符'\0'),当前文件位置移至下一行,虽然23大于当前行上字符总和,可是不会继续到下一行。而下一次调用fgets()继续读取的时候是从下一行开始读。

2序例


  1. #include <string.h>
  2. #include <stdio.h>
  3. int main(void)
  4. {
  5.     FILE *stream;
  6.     char string[] = "This is a test";
  7.     char msg[20];
  8.     /* open a file for update */
  9.     stream = fopen("DUMMY.FIL", "w+");
  10.     /* write a string into the file */
  11.     fwrite(string, strlen(string), 1, stream);
  12.     /* seek to the start of the file */
  13.     fseek(stream, 0, SEEK_SET);
  14.     /* read a string from the file */
  15.     fgets(msg, strlen(string)+1, stream);
  16.     /* display the string */
  17.     printf("%s", msg);
  18.     fclose(stream);
  19.     return 0;
  20. }


fgets函数用来从文件中读入字符串。fgets函数的调用形式如下:fgets(str,n,fp);此处,fp是;str是存放在字符串的起始地址;n是一个int类型。 函数的功能是从fp所指文件中读入n-1个字符放入str为起始地址的空间内;如果在未读满n-1个字符之时,已读到一个换行符或一个EOF(文件结束标 志),则结束本次读操作,读入的字符串中最后包含读到的换行符。因此,确切地说,调用fgets函数时,最多只能读入n-1个字符。读入结束后,系统将自动在最后加'\0',并以str作为函数值返回。
函数原型是:char *fgets(char *s, int n, FILE *stream);

3函数使用

同时可以用作键盘输入:fgets(key,n,stdin)且还必须:key[strlen(key)-1]='\0'
与gets相比使用这个好处是:读取指定大小的数据,避免gets函数从stdin接收字符串而不检查它所复制的缓存的容积导致的缓存溢出问题.

阅读(1013) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~