fgets
从指定的文件中读一行字符到调用者提供的缓冲区中,gets
从标准输入读一行字符到调用者提供的缓冲区中。
#include <stdio.h> char *fgets(char *s, int size, FILE *stream); 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'
组成完整的字符串。
如果文件中的一行太长,fgets
从文件中读了size-1
个字符还没有读到'/n'
,就把已经读到的size-1
个字符和一个'/0'
字符存入缓冲区,文件中剩下的半行可以在下次调用fgets
时继续读。
如果一次fgets
调用在读入若干个字符后到达文件末尾,则将已读到的字符串加上'/0'
存入缓冲区并返回,如果再次调用fgets
则返回NULL
,可以据此判断是否读到文件末尾。
注意,对于fgets
来说,'/n'
是一个特别的字符,而'/0'
并无任何特别之处,如果读到'/0'
就当作普通字符读入。如果文件中存在'/0'
字符(或者说0x00字节),调用fgets
之后就无法判断缓冲区中的'/0'
究竟是从文件读上来的字符还是由fgets
自动添加的结束符,所以fgets
只适合读文本文件而不适合读二进制文件,并且文本文件中的所有字符都应该是可见字符,不能有'/0'
。
fputs
向指定的文件写入一个字符串,puts
向标准输出写入一个字符串。
#include <stdio.h> 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'
到标准输出。