以字符串为单位的I/O函数
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'组成完整的字符串。(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序例
-
#include <string.h>
-
#include <stdio.h>
-
int main(void)
-
{
-
FILE *stream;
-
char string[] = "This is a test";
-
char msg[20];
-
/* open a file for update */
-
stream = fopen("DUMMY.FIL", "w+");
-
/* write a string into the file */
-
fwrite(string, strlen(string), 1, stream);
-
/* seek to the start of the file */
-
fseek(stream, 0, SEEK_SET);
-
/* read a string from the file */
-
fgets(msg, strlen(string)+1, stream);
-
/* display the string */
-
printf("%s", msg);
-
fclose(stream);
-
return 0;
-
}
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接收字符串而不检查它所复制的缓存的容积导致的缓存溢出问题.
阅读(1044) | 评论(0) | 转发(0) |