}
return 0;
}
按照我的理解的话,那么文件中总共11个字母,当文件指针停在‘\t’之后,k之前的时候
,刚好是第八次,第九次getline的时候,由于在读过k之后,遇到了文件结束符,所以get
指针应该停留在k之后,这个时候再getline的话应该是无效的,但是输出结果跟我想的不
一样:
a
b
c
d
e
f
g
h
i
j
k
k
k
k
k
这说明第九次getline之后,get指针所指向的位置并没有改变,这说明我想的思路有问题
,于是我在网上看了getline函数的源码,其中有一篇注释比较好的:
_Myt& getline(_Elem *_Str, streamsize _Count, _Elem _Delim)
{// get up to _Count characters into NTCS, discard _Delim
_DEBUG_POINTER(_Str); //判断传入指针的合法性
ios_base::iostate _State = ios_base::goodbit;
_Chcount = 0; //从输入流中读取的字符数
const sentry _Ok(*this, true);
/*注:上面这句很关键,它关系到下面的if是否执行,也就是是否读输入流。这句从
语法上看,是
sentry是一个class, _Ok是sentry类的一个const对象,构造这个对象时需要传入两个
参数
第一个是流对象自身的引用,第二个表示对空白字符(如空格、制表符)的处理方式
,为true时意味着不忽略空白字符,即一个字符一个字符的从输入流中提取。
*/
if (_Ok && 0 < _Count)
/*
**************************************************************************
* sentry类内部重载了一个类型转换运算符,它把sentry类的实例转换成了一个bool
表达式。
* 这个表达式返回sentry类的私有成员_Ok的值。
bool sentry::operator bool() const
* { // test if _Ipfx succeeded
* return (_Ok);
* }
* _Ok这个成员的值由sentry类的构造函数
* 在初始化时设置,设置的过程比较麻烦,这里不做赘述(其实我也没看十分明白)。
* 但可以肯定的是,当输入流的状态是正常时,这个成员的值也是true,
* 反之,则是false。
*
* _Count是调用者传入的第二个参数,这里用做循环计数器的初值,以后每读一个字
符,
* _Count的值会减一。
****************************************************************************
**/
{
// state okay, use facet to extract
int_type _Metadelim = _Traits::to_int_type(_Delim);
int_type _Meta = _Myios::rdbuf()->sgetc();//从输入流读一个字符
for (; ; _Meta = _Myios::rdbuf()->snextc()) //snextc()从输入流中读取下一
个字符
if (_Traits::eq_int_type(_Traits::eof(), _Meta))
{// end of file, quit
_State |= ios_base::eofbit;
break;
}//注:遇到文件尾,getline结束
else if (_Meta == _Metadelim) {
// got a delimiter, discard it and quit
++_Chcount; //读取字符数+1
_Myios::rdbuf()->sbumpc();
/*注:上面这句把结束符读掉了,如果不指定结束符,那就是把'\n'读掉了
。
但回车符本身并没有拷贝到缓冲区中,
这样下次的读操作将从回车符后面的第一个字符开始,
*/
break;
}/* 注:遇到结束符,getline结束,注意这里的顺序,它是先判断是否遇到结束
符,后判断是否读入了指定个数的。 */
else if (--_Count <= 0)
{// buffer full, quit
_State |= ios_base::failbit;
break;
}
//注:读到了指定个数,执行到这里已经隐含了在指定个数的最后一位仍然不是
结束符,
//因此该部分将输入流状态置为了错误。
//这直接导致了接下来的getline(或者get)以及>>运算符等读操作都不能正确执
行)
else {
// got a character, add it to string
++_Chcount; //读取字符数加1
*_Str++ = _Traits::to_char_type(_Meta);
}//注:这一分支将读取到的单个字符拷贝到缓冲区中
}
*_Str = _Elem(); //
/* add terminating null character /*注:前面这句为字符串加入了终止符'\0'
因为_Elem()构造了一个ascii码为0的字符对象*/
_Myios::setstate(_Chcount == 0 ? _State | ios_base::failbit : _State);
/*注:如果没有读入任何字符,要保持执行这一次getline之前的输入流状态,
否则根据这一次getline执行的情况,设置输入流为相应状态。 */
return (*this); //返回输入流对象本身
}
但是我觉得这其中还是有问题,因为:
sbumpc: advances the get pointer and returns the character pointed by it
before the call.
snextc: advances the get pointer and returns the character pointed by it
after the call.
由于是传引用,所以不论调用哪个,都会改变原文件流中get的指针所指向的位置。而且,
告诉大家一个更为惊奇的结果便是:
下面程序:
int main(){
int n = 6;
string tem;
ifstream infile("test.txt");
for(int i = 0;i
getline(infile,tem);
//getline(infile,tem,'\t');
cout<
}
return 0;
}
的输出结果为:
a
b
c
d
e
f
g
h
i
j
k
i
j
k
i
j
k
i
j
k
不管按照我的想法还是按照对上面源码的理解,结果都不应该是这个样子。是源码错了,还
是我的理解有问题?希望知道的朋友能指导一下。
==========================================================================
好吧,可能是编译器的问题,用比的编译器编译运行了一下,结果和我的想法是一致的,跟源码所要表达的也是一致的
,所以我原先的想法是没错的,结贴啦~
所以如果你不断的从文件流中getline的话,如果你想判断是否已经达到文件结尾的话,那么只需判断getline所得到的字符串是否为
空就ok了~
再补充一下,由于getline函数将istream参数作为返回值,和输入操作符一样也把它作为判断条件。所以如果到达文件结尾的话,那么返回的文件流包含的字符为空,这个false是等价的 ,所以我们也可以用while(getline(infile,str))来对文件流是否达到结尾进行判定。