feof和EOF的字符被重复读取问题的思考

void main()
{
  PNode pNode;
  FILE *fp=fopen("1.txt","r");
  pNode=Create(i);
  while(getc(fp)!=EOF) {
    int i;
    fscanf(fp,"%d",&i);
    pNode=Add(i,pNode);
  }
  fclose(fp);
  Print(pNode);
}

(问题源码如上所示)

问题介绍

我在温习C语言时,准备尝试编写单链表的结构,但是写到上面一段代码,运行后发现,文件的最后一个字符被重复读取了,焦头烂脑思考了一会儿,并且尝试搜集资料,写了这个博客。

问题思考

这个问题根源在文件读取上,因为我尝试了直接向链表中添加数据是没有任何问题的。而本程序使用了两个文件读取函数,即getc和fscanf,这两个函数的交错使用在一定程度上是程序结构有点混乱,这可能是我当时编程的时候没有用心思考造成的。

如果文件自身没有设置EOF的话,我们的getc函数遇到‘\0‘之后,将设置为EOF,再进入循环体一次,而fscanf已经读取不到有效字符了,因此返回EOF,但是此时i的值仍为最后一个整数的值,因此将再次读取该值。如果将下面一句

getc(fp)!=EOF

改为!feof(fp),则问题仍会出现,原因同上。

代码解决之道

正确的做法应该是下面一段代码:

PNode pNode;
  //从文件中读取数据并添加到链表中
  FILE *fp=fopen("1.txt","r");
  int count=0;
  int i;
  pNode=Create();
  while(fscanf(fp,"%d",&i)!=-1) {
    pNode=Add(i,pNode);
  }
  fclose(fp);
  Print(pNode);

这样的话,重复读取字符的问题就不会出现了。因为此时会直接判断是否是有效字符,若不是,直接退出while循环,因此最后一个字符只会被读取一次。

总结

用C语言实现数据结构确实能够学到很多东西,越是底层的语言,越能锻炼我的代码能力。本次尝试自己完全独立编写单链表的基本操作,基本上可以实现感谢C语言,感谢计算机!

时间: 2024-10-07 01:43:05

feof和EOF的字符被重复读取问题的思考的相关文章

理解feof与EOF

feof(feof msdn) feof用于判断文件结尾.头文件<cstdio>.使用方法是feof(fp),fp为指向需要判断的文件的指针.如果不到文件结尾,返回0值:如果是文件结尾,返回非0. 使用feof判断文件结尾一定要非常注意以下一点: 假设文件包含10字节,并且你读取了十字节,调用feof函数,函数返回值均为0,这是因为尽管文件指针这时已经指向文件尾了,但是你没有试图越过文件尾读取数据,只有当你尝试了读取第十一个字节时,调用feof,函数才会返回0. 因此,使用feof常用的逻辑结

解决java读取大文件内存溢出问题、如何在不重复读取与不耗尽内存的情况下处理大文件

1.传统的在内存中读取 读取文件行的标准方式是在内存中读取,Guava 和Apache Commons IO都提供了如下所示快速读取文件行的方法: 1 2 3 Files.readLines(new File(path), Charsets.UTF_8); FileUtils.readLines(new File(path)); 这种方法带来的问题是文件的所有行都被存放在内存中,当文件足够大时很快就会导致程序抛出OutOfMemoryError 异常. 例如:读取一个大约1G的文件: 1 2 3

[华为机试练习题]15.删除重复字符/删除重复字符串

题目 题目标题: 删除重复字符 给定一个字符串,将字符串中所有和前面重复多余的字符删除,其余字符保留,输出处理后的字符串.需要保证字符出现的先后顺序,并且区分大小写. 详细描述: 接口说明 原型: int GetResult(const char *input, char *output) 输入参数: input 输入的字符串 输出参数(需考虑指针指向的内存区域是否有效): output 输出的字符串 返回值: 0 成功 -1 失败及异常 举例: 输入: abadcbad,那么该单词中红色部分的

js实现过滤重复字符和重复数组-javascript技巧

js实现过滤重复字符 <script type="text/javascript"> <!-- String.prototype.noRepeatStr=function(){ var tempArr=new Array(); for(var i=0;i<this.length;i++){ if(tempArr.join('').indexOf(this.charAt(i))==-1) tempArr[tempArr.length]=this.charAt(i)

feof()和EOF的用法—— C中文件结尾的判断

查看 stdio.h 可以看到如下定义: #define EOF (-1) #define _IOEOF 0x0010 #define feof(_stream) ((_stream)->_flag & _IOEOF) 由此可以看出,这两种方式的原理是不同的. 在这里先说下EOF和feof()这个两个宏定义,在我们学的课本中有这样的描述. EOF是不可输出字符,因此不能在屏幕上显示.由于字符的ASCII码不可能出现-1,因此EOF定义为-1是合适的.当读入的字符值等于EOF时,表示读入的已不

蓝桥杯.取字符(去掉重复的使用set list实现)

题目描述: 从键盘读入一个由字母构成的串(不大于30个字符). 从该串中取出3个不重复的字符,求所有的取法. 取出的字符,要求按字母升序排列成一个串. 不同的取法输出顺序可以不考虑. 例如: 输入: abc 则输出: abc 输入: abcd 则输出: abc abd acd bcd 输入: abcaa 则输出: abc package ccf; import java.util.ArrayList; import java.util.HashSet; import java.util.Link

统计某字符(串)重复出现次数

USE [master] GO/****** Object:  UserDefinedFunction [dbo].[CharRepeat]    Script Date: 04/06/2016 17:32:06 ******/SET ANSI_NULLS ONGOSET QUOTED_IDENTIFIER ONGO-- =============================================-- 返回字符串中某字符出现次数,返回结果为INT,@str 字符串 @sub 目标字

Java数组去掉重复的方法集

经常用到,有时候不只是简单的基本类型,那种可以用set集合去重,好多时间用到的是我们自定义的类型,下面举个例子(我这儿就那int举例了): 方法一. 这种类似与选择排序算法,首先我们取i值,然后将i之后的所有重复的去掉.具体实现如下: import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; /** * 创建时间:2014-11-18 下午3:26:35 * * @author zhangtianyou *

多线程下不重复读取SQL Server 表的数据

在进行一些如发送短信.邮件的业务时,我们经常会使用一个表来存储待发送的数据,由后台多个线程不断的从表中读取待发送的数据进行发送,发送完成后再将数据转移到历史表中,这样保证待发送表的数据一般情况下不会太多.如待发送表结构为: Create Table SMS(ID int not null identity(1,1),Content varchar(1024),Status int not null,CreateTime datetime); Status 取值:0未读取 1已读取 这样设计的好处