C语言程序中如何正确使用feof函数
2015-09-21张吴波史旅华湖北汽车工业学院电子信息工程学院十堰442002
张吴波,史旅华(湖北汽车工业学院电子信息工程学院,十堰 442002)
C语言程序中如何正确使用feof函数
张吴波,史旅华
(湖北汽车工业学院电子信息工程学院,十堰 442002)
0 引言
文件是存储在外部介质 (如磁盘)上的数据的集合,这些数据能长期保留,可以随时存取。在C语言程序设计中经常需要将处理的数据保存在文件中,并从文件中读取数据。C语言提供了许多的标准函数进行文件的操作,在笔者多年的《C语言程序设计》讲授中,发现学生对文件的操作不熟悉,读写文件经常出错,从文件中读取数据时尤为突出。
1 文件读取与文件结构体
C语言中对文件进行读取操作时,先打开文件。C语言提供了fopen()函数来打开文件,其返回值是一个FILE类型的文件指针。然后再通过C语言提供的文件读取函数,例如fgetc()、fgets()、fscanf()、fread()等函数,从文件中将数据读取到程序的内存空间。
理解文件读取函数是如何从文件中读取数据,对正确地从文件中读取数据非常重要。由于磁盘是慢速设备,如果每向磁盘写入一个字节或读出一个字节的数据,都要启动磁盘操作,将会大大降低系统的效率,而且还会对磁盘驱动器的使用寿命带来不利影响。因此,在文件系统中往往使用缓冲技术,即系统在内存中为每个正在使用的文件开辟一个缓冲区,利用缓冲区完成文件读写操作。打开文件是在文件与程序之间建立起联系,程序把所要操作的文件的有关信息,如文件名、文件操作方式等通知给系统;系统根据文件的有关信息为该文件分配相应的文件缓冲区[1]。
FILE是在stdio.h中定义的结构体类型,它包含了与文件操作有关的信息,如文件对应的内存缓冲区地址、读写位置、操作方式、文件结束标志等。当打开一个文件时,系统自动为每个文件开辟一个“文件信息区”,用于存放上述信息。C程序用不同的FILE结构管理每个文件。在VC 6.0中,FILE结构体的定义如下:
其中成员base表示文件缓冲区的起始位置,成员_ptr是文件位置指针,指示文件当前的读写位置。从文件中读取数据后,它就向后移动相应的字节。_flag表示文件当前的状态,其中的不同二进制位代表文件中不同的状态,例如文件是否结束、文件读取是否出错等[2]。
2 feof函数工作机制
由于文件中可能存放多个数据,因此在使用这些函数从文件读取数据时,一般都使用循环的方式。那么在循环中如何确定文件读取已经结束呢?C语言提供了feof()函数,用于判断文件是否结束:如果文件读取结束,函数返回1(真),否则返回0(假)。因此在读取文件时,经常使用该函数判断[3]。
但是广大C语言初学者经常会碰到如下的情况,而对编写读取文件的程序产生困惑。例如:程序pro1.c读取该文件的内容,并显示在屏幕上。
在文件data.txt的内容为ABCDEFGH和内容为ABCDEFG时,程序运行结果截然不同,如图1所示。
图1 pro1.c程序运行结果
从上面的运行结果发现,在第一种情况下,程序多输出了一次。为什么会这样呢,这是由于feof()函数给出返回值的规则造成的。在VC 6.0中,feof()函数根据文件结束标志返回结果,如果文件结束标志被置为1,则返回1,否则返回0。那么文件结束标志什么时候被置为1呢?在读取文件时,即使文件位置指针 (fp->_ptr)指向了文件末尾(虽然文件中的数据都已经被读出),文件结束标志仍为0,只有再发生读操作,它才被置为1[4]。
上述的pro1.c程序中,当data.txt文件中的数据为ABCDEFGH时,文件结束标志的变化过程如图2所示。
图2 _ptr指针移动与文件结束标志变化
从上面的示意图可以看出,当第二次读取时,fgets()恰好从文件读取4个字符,而文件位置指针_ptr虽然已经指向了文件末尾,因为此时不再从文件中读取数据,文件结束标志仍然为0,所以feof()函数返回值为0。因此程序会执行第三次循环,再调用fgets()函数从文件中读取数据时,系统才将文件结束标志置为1,并改变_ptr指向,再使用feof函数判断时,函数返回1。
3 正确使用feof函数
从上面的分析可以看出,使用feof()函数判断文件是否结束时,可能会发生这样的情况:实际文件中的最后一个数据已经读取完毕,但feof()函数仍返回0,如果根据feof()函数的返回值判断,此时会导致多读一次文件而产生错误的结果。那么如何正确使用feof()函数,以避免产生错误呢?这个错误产生的根本原因是因为feof()函数使用的时机不对,一般的使用方法可以按照图3所表示的流程使用。
上面的方法对于使用fgetc()函数、fscanf()函数、fread()函数可以正确地进行文件的读取。但是对于fgets()函数,由于最后一次从文件中读取的字符个数可能会比参数指定的读取字符个数少,而此时文件结束标志会置为1。按照按照上面的流程,则会漏掉对最后读取数据的处理。在这种情况下,如果使用feof()函数作为循环的结束条件时,须结合文件读取函数的返回值进行判断。
图3 使用feof函数一般的流程
将pro1.c程序修改如下:
或者修改如下:
上面修改后的程序,当 data.txt中的内容为ABCDEFGH或者为ABCDEFG时,都能正确地读取、显示文件中的数据。其中第二个修改的程序是在循环体中结合fgets()函数的返回值,判断循环是否结束。
4 结语
在《C语言程序设计》中,从文件中读取数据是一个重点和难点。很多学生在使用文件编程时,经常出现错误。尤其是循环读取数据时,使用feof()函数判断文件读取是否结束,更为突出。究其原因是因为学生对C语言中文件读写机制不熟悉,对feof()函数返回结果的规则不了解。而这些知识点在许多教材和参考书中又很少提及,因此导致学生在具体应用时出现了错误。
本文分析了feof()函数的工作机制和文件结束标志在文件读取过程中的修改过程。然后结合二者,提出了正确使用feof()函数的方法。可以帮助学生加深对文件读取的理解,掌握对文件读取操作的正确方法。
[1]史旅华,张吴波.C语言程序设计教程[M].人民邮电出版社,2014.8
[2]黄瑛.C语言教材中对feof函数的常见误解与误用[J].科技文汇,2012.5
[3]王锐.C语言存取文本文件技术探索[J].科技创新沦坛[J],2010.24
[4]林智勇.C语言案例教学之文件读写[J].现代计算机,2014.6
C Programming;File;FILE Struct;feof Function
How to Use the feof Function Correctly in C Language
ZHANG Wu-bo,SHI Lv-hua
(School of Electrical&Information Engineering,Hubei University of Automotive Techonlogy,Shiyan 442002)
1007-1423(2015)10-0053-04
10.3969/j.issn.1007-1423.2015.10.015
张吴波(1977-),男,湖南邵阳人,讲师,研究方向为软件开发
2015-02-26
2015-03-12
针对在C语言课程中学生从文件中读取数据时经常出错的现象,分析FILE结构体的意义和从文件中读取数据的工作机制。然后结合具体程序,指出在应用feof函数判断文件结束时的错误,并分析feof函数的工作机制,提出一种正确使用feof函数进行文件读取的方法。
C语言程序设计;文件;FILE结构体;feof函数
史旅华(1963-),男,浙江宁波人,副教授,研究方向为图形图像处理研究
Focuses on the phenomenon that problem has happened when students read data from file using C language.Analyzes the importance of the FILE struct,and analyzes the process of reading data from file in C.According to some specific examples,points out the mistakes of using feof function to judge the end of reading data.Points out the process of judging end of file with feof function.At last proposes a way that how to correctly use the feof function to read data from file.