getline成员函数分析

今天一个学生写了如下代码段,其目的将一个文本文件的内容输出到屏幕上。

ifstream in("file3.txt")
char buf[3];
while(!in.eof()) 
 {
       in.getline(buf,  sizeof(buf));
	cout<<buf<<endl;
}

file3.txt的内容如下:

abc
efg

在执行的时候程序输出一个ab之后便进入了死循环。原因何在?

经过一个小时的查资料和看代码,终于大致搞清问题所在,与getline的实现机制有关。

getline成员函数的声明如下

basic_istream<Elem, Tr>&

getline(
     char_type *_Str, 
     streamsize _Count, 
      char_type _Delim
);
第一个参数是字符缓冲区地址,第二个是缓冲区长度,第三个是分隔符(默认是回车)。

其实现的大致流程是:

1、首先判断istream的failbit位是否为1,为1的话意味着输入流的状态有错误,则不进行读操作,getline函数结束执行

2、从当前位置开始从输入流中依次读取单个字符并拷贝到缓冲区,直到遇到下列条件满足时,循环结束。

(1)遇到文件尾时停止读操作,并设置流对象的结束标记为1

(2)读到调用者指定的分隔符时,此时将分隔符之前的字符拷贝到缓冲区中,但分隔符本身不拷贝进去,并且下次读操作将从分隔符后的下一个字符开始。

(3)已经读了n-1个字符(n是调用者传入的第二个实参_Count的初值),此时要把流对象的错误标志位置1(为什么要这么干,我也不知道,个人觉得这么设计不太合理....)

当循环结束后,gelline函数会在字符串的尾部加一个C风格的结束符'\0'。


这样,学生遇到的现象就可以解释了。

首先,由于file3.txt文件是存在的,所以in对象开始时的状态是正常的,因此第一次getline将会执行,由于缓冲区的长度是3,因此在读完ab两个字符之后getline内部的循环便终止了。此时getline会把in对象的failbit设为1,但文件还未读到尾部,所以in.eof()为false,这样在第二次进入while循环体时,循环条件!in.eof()为true,于是继续执行getline函数

,但是由于第一次的getline操作已经把in对象的failbit设为1,第二次的getline便不进行任何读操作了,此时流的指针和流的状态均未发生变化,于是第三次循环时与第二次循环一样,循环条件为真,可以进入循环体,in对象的failbit设为1,getline函数不进行读取操作,如是反复,便导致了死循环。

知道了病因,于是便有了下面的解决方案

while(!in.eof())
{
	in.getline(buf,sizeof(buf));//将
	if(in.fail() && in.gcount()==(sizeof(buf)-1))  
           in.clear();
       cout<<buf<<endl;
}
这里的clear成员函数的作用是将in对象的状态设回正常状态。gcount函数返回上次读操作中从输入流中提取的字符数(包括分隔符)。

请读者自行分析和改进这个解决方案。




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值