首页 > 编程知识 正文

feof()函数的功能是,feofe2o3fe3o4三种化合物

时间:2023-05-06 12:59:55 阅读:224798 作者:203

一、查看 stdio.h 可以看到如下定义:

*#define EOF (-1)***
#define _IOEOF 0x0010
#define feof(_stream) ((_stream)->_flag & _IOEOF)**

由此可以看出,这两种方式的原理是不同的。

在这里先说下EOF和feof()这个两个宏定义,在我们学的课本中有这样的描述。
EOF是不可输出字符,因此不能在屏幕上显示。由于字符的ASCII码不可能出现-1,因此EOF定义为-1是合适的。当读入的字符值等于EOF时,表示读入的已不是正常的字符而是文件结束符,但这适用对文本文件的读写。在二进制文件中,信息都是以数值方式存在的。EOF的值可能就是所要处理的二进制文件中的信息。这就出现了需要读入有用数据却被处理为“文件结束“的情况。为了解决这个问题,C提供了一个feof()函数,可以用它来判断文件是否结束。feof(fp)用于测试fp所指向的文件的当前状态是否为“文件结束”。如果是,函数则返回的值是1(真),否则为0(假)。

说了这两个的定义,肯定还对二进制文件和文本文件的区别有些模糊那现在就回顾下这两个文件的概念。C语言支持的是流式文件,它把文件看作由一个一个的字符(字节)数据组成的序列。根据数据的组织和操作形式,可以分为ASCII文件和二进制文件。
ASCII文件又称为文本文件,它是在一个字节的存储单元上存放一个字符(在外存中存放的是该字符的ASCII码,每个字符将占一个字节)。
二进制文件是把内存中的数据按其在内存中的存储格式在磁盘上原样保存。
对字符而言,由于其外存存储格式和内存表示格式相同,所以,在外存上也存放每个字符的ASCII码。

但是说EOF只能用于文本文件,其实不然,这点不是特别的准确,还要看定义的变量的类型。

下面这段程序对文本文件和二进制文件都可以:

int c;
while((c=fgetc(fp)) != EOF)
{
printf(“%X/n”, c);
}
如果读到了FF,由于c定义为int型,所以实际上c=0x000000FF,不等于EOF(-1=0xFFFFFFFF),因此不会误判为文件结尾。

但是如果把c定义为char类型,就有可能产生混淆了。
char c;
while((c=fgetc(fp)) != EOF)
{
printf(“%X/n”, c);
}
因为文本文件中存储的是ASCII码,而ASCII码中FF代表空值(blank),一般不使用,所以如果读文件返回了FF,说明已经到了文本文件的结尾。但是如果是二进制文件,其中可能会包含FF,因此不能把读到EOF作为文件结束的条件,此时只能用feof()函数。

在VC里,只有当文件位置指针(fp->_ptr)到了文件末尾,然后再发生读/写操作时,标志位(fp->_flag)才会被置为含有_IOEOF。然后再调用feof(),才会得到文件结束的信息。
因此,如果运行如下程序:
char c;
while(!feof(fp))
{
c = fgetc(fp);
printf(“%X/n”, c);
}
会发现多输出了一个FF,原因就是在读完最后一个字符后,fp->flag仍然没有被置为_IOEOF,因而feof()仍然没有探测到文件结尾。直到再次调用fgetc()执行读操作,feof()才能探测到文件结尾。这样就多输出了一个-1(即FF)。

正确的写法应该是:
char c;
c = fgetc(fp);
while(!feof(fp))
{
printf(“%X/n”, c);
c = fgetc(fp);
}

二、以linux平台下的vim创建的文件为例,当读取指定文件中的内容时,文件的格式为:
内容+EOF
其中 EOF为vim文件内容的结束标志。
每当用C语言读取文件内容时,文件指针要指向字符EOF之后才能判断文件已经结束。所以EOF内容会被读取,读取到的EOF通常会给我们带来困扰,如输出时会多输出一行。
为了解决多读取的EOF字符(在文件中不可见),我们用一个小小的逻辑算法来避免EOF字符带来的困惑,如打印读取的文件内容时不将读取到的EOF字符输出,或避免在读取到EOF字符(读取此字符不成功)后无判断文件是否结束的操作而又将上一次读取到的数据输出。

1.文件指针 文件内容

如data.in文件中的内容如下:
12345678
23456789
那么当用指针打开此文件并用相关的C语言文件操作函数来读取这个文件时,C语言文件指针执行过程(移位)如下:
当打开文件时,文件指针指向文件中的第一个字符
如FILE *fp = fopen(“data.in”, “r”);要是打开data.in文件成功之后,文件指针fp就会指向文件中的第一个字符:’1’。
每根据 要求(读一个字符,一行字符串等) 读取一次文件内容时,文件指针将指向下一个(临近)的字符。
如data.in中的内容,此时用fgets(ar, 100, fp);语句后(读取文件中的一行字符串),文件指针将指向下一行的字符:’2’
当文件指针指向EOF时,并不会认为文件内容已经结束。当指针指向EOF后一位时(把EOF读取后),此时文件内容才算结束。
如在data.in中,把字符’9’成功读取后,文件指针指向EOF字符。此时若判断文件是否结束,则不为结束;只有把EOF字符读取之后(文件指针指向EOF后时),再判断文件是否结束时,才会判断为结束。

2.正确使用feof()

#include <stdio.h> #define SIZE 100 #define FILENAME "data.in" int main(void) { int ln; FILE *fp; char ar[SIZE]; ln = 0; if( (fp = fopen(FILENAME, "r") ) == NULL){ printf("Can not open file: %sn", FILENAME); return -1; } while( !feof(fp) ){ fgets(ar, SIZE, fp); //If read EOF, //Do not record the line`s number, //Do not print the content to screen if( feof(fp) ){ break; } ln++; printf("%s", ar); } printf("The file`s line is %dn", ln); fclose(fp); return 0; }

这是一个打开与本源程序在同一个目录下叫data.in文件的程序。并读取data.in中的全部内容,并统计行数。
data.in中的内容如1中所述。
编译、运行此程序后的结果为:
12345678
23456789
The file`s line is 2
分析结果:
(1)此程序将data.in中可见内容照样输出(用fgets函数读取文件内容时,ar数组已经包含回车符,故不需要在printf打印语句中再添加回车),并正确统计了其内容行数。
(2)能正确将文件内容输出的关键语句是”if( feof(fp) ){break;}”需要将此语句加在”行数自增,打印行内容(ln++;printf(“%s”, ar))”语句之前。

3.非正确使用feof()

若将2中代码中的”if( feof(fp) ){break;}”语句去掉或者是写到”ln++;printf(“%s”, ar)”之后,则程序将不会得到预期效果。
a.将2中代码中的”if( feof(fp) ){break;}”语句去屏蔽,再编译运行程序得到结果:
12345678
23456789
23456789
The files line is 3
b.将将2中代码中的"if( feof(fp) ){break;}"语句写到"ln++;printf("%s", ar)"语句之后,再编译运行程序得到结果:
12345678
23456789
23456789
The files line is 3
分析结果:
造成a,b结果的原因在于:当读取EOF字符时,文件指针已经指向EOF之后,但此时没有进行读取文件内容是否结束的判断,从而没有进一步中断while循环,使fgets()函数读取EOF字符读取失败(不能讲字符EOF读入到数组ar中),从而ar数组里面的内容还是上一次读取的内容。所以当输出ar时,ar的值为上一次字符串值,并且ln++语句得以执行。故而是多输出文件中最后一行数据的结果!

总结:
在用非手动输入数据的程序手段进行数据的获取时(如读文件时,需要结合文件内容格式和相应函数功能(操作过程)来获取准确的数据)。有时候一字符只差,全程序皆输也!

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。