在我的印象中,getline函数经常出现在自己的视野里,模糊地记得它经常用来读取字符串
 
。但是又对它的参数不是很了解,今天又用到了getline函数,现在来细细地总结一下:
 
首先要明白设计getline函数的目的,其实很简单,就是从流中读取字符串。而且读取的方
 
式有很多,包括根据限定符,根据已读取的字符的个数。从这个函数的名称来看,它的直观
 
意义是从流中读取一行,但是大家不要被这表面的现象所迷惑。其实如果让我来为这个函数
 
去一个名字的话,或许我会取一个getString,因为它的目的本来就是从流中读取字符的序
 
列,而不是像get函数那样一次读取一个字符。
 
另外要注意,C++中有两个getline函数,一个是在string头文件中,定义的是一个全局的
 
函数,函数声明是istream& getline ( istream& is, string& str, char delim )与
istream& getline ( istream& is, string& str );另一个则是istream的成员函数,函
 
数声明是istream& getline (char* s, streamsize n )与istream& getline (char* 
 
s, streamsize n, char delim );注意第二个getline是将读取的字符串存储在char数组
 
中而不可以将该参数声明为string类型,因为C++编译器无法执行此默认转换。
 
下面根据一个例子简单地介绍一下该函数:
test.txt文件如下所示:
 
abcd
efgh
ijk
 
现在先尝试全局函数getline。从函数声明中我们观察到两种函数声明的不同主要体现在参
 
数的个数上,如果是两个参数的话,那么默认的限定符便是‘\n’了,但是如果声明了限
 
定符,'\n'是否仍然有效呢?我写了如下程序做测试:
 
int main(){
int n = 6;
string tem;
ifstream infile("test.txt");
for(int i = 0;i<n;i++){
//getline(infile,tem);
getline(infile,tem,'\t');
cout<<tem;
}
return 0;
}
 
输出结果是:
abcd
efg
 
从中可以看出换行符确实失效了。所以getline函数的限定符只有一个,是相互覆盖的。
 
再来看一下istream的getline函数:
 
int main(){
char a[3];
ifstream infile("test.txt");
infile.getline(a,3,'c');
cout<<a;
}
 
输出结果是a
其实istream的getline是在全局函数的getline函数的基础上,又多了一个终止读取的条
 
件,即根据已读取的字符的个数来判定,实际上是读取n-1个字符,因为最后要为‘\0’留
 
下一个位置。其他地方二者基本相同。
 
原理想必也很简单。每一次getline,文件指针都不断向下走,相当于不断的调用get函数
 
并且将已经读取的字符保存下来。当遇到限定符或者已读取的字符个数达到了参数的要求(
 
或者是由于文件的原因),那么便终止读取。如果是碰到了限定符,那么该字符便会被 
 
extracted and discarded,也就是文件指针向下再移一位,但是并不保存该字符,也就
 
是每次getline之后,文件指针会停留在限定符的后面(遇到限定符的情况)。
 
但是看下面的这个情况:
 
int main(){
int n = 13;
string tem;
ifstream infile("test.txt");
for(int i = 0;i<n;i++){
//getline(infile,tem);
getline(infile,tem,'\t');
cout<<tem<<endl;
}
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<n;i++){
getline(infile,tem);
//getline(infile,tem,'\t');
cout<<tem<<endl;
}
return 0;
}
的输出结果为:
abcd
efgh
ijk
ijk
ijk
ijk
 
不管按照我的想法还是按照对上面源码的理解,结果都不应该是这个样子。是源码错了,还
 
是我的理解有问题?希望知道的朋友能指导一下。
 
 
==========================================================================
好吧,可能是编译器的问题,用比的编译器编译运行了一下,结果和我的想法是一致的,跟源码所要表达的也是一致的
,所以我原先的想法是没错的,结贴啦~
所以如果你不断的从文件流中getline的话,如果你想判断是否已经达到文件结尾的话,那么只需判断getline所得到的字符串是否为
空就ok了~
再补充一下,由于getline函数将istream参数作为返回值,和输入操作符一样也把它作为判断条件。所以如果到达文件结尾的话,那么返回的文件流包含的字符为空,这个false是等价的 ,所以我们也可以用while(getline(infile,str))来对文件流是否达到结尾进行判定。

getline函数(精华版)的更多相关文章

  1. 一看就懂的ReactJs入门教程(精华版)

    一看就懂的ReactJs入门教程(精华版) 现在最热门的前端框架有AngularJS.React.Bootstrap等.自从接触了ReactJS,ReactJs的虚拟DOM(Virtual DOM)和 ...

  2. ReactJs入门教程-精华版

    原文地址:https://www.cnblogs.com/Leo_wl/p/4489197.html阅读目录 ReactJs入门教程-精华版 回到目录 ReactJs入门教程-精华版 现在最热门的前端 ...

  3. 【知识学习】Sublime Text 快捷键精华版

    Sublime Text 快捷键精华版 Ctrl+Shift+P:打开命令面板 Ctrl+P:搜索项目中的文件 Ctrl+G:跳转到第几行 Ctrl+W:关闭当前打开文件 Ctrl+Shift+W:关 ...

  4. Replace 删除、替换函数精解示例

    '************************************************************************* '**模 块 名:Replace函数精解示例 '* ...

  5. Filter 数组过滤函数精解示例

    '************************************************************************* '**模 块 名:Filter 数组过滤函数精解示 ...

  6. Join函数 及Split函数精解示例

    '************************************************************************* '**模 块 名:Join函数 及Split函数精 ...

  7. getline函数彻底说明

    因为之前每次使用这个函数都要在网上查一遍,觉得很麻烦,这次就认真地整理一下,希望写完之后就记住. getline函数其实有两个: 一个是全局函数,include<cstring>, 原型是 ...

  8. getline()函数

    这是一篇关于getline()函数的博客,以总结对输入输出流的掌握,不再在这些问题上栽跟头~ -------------------------- 1.首先我们知道,getline()函数的基本作用, ...

  9. C/C++中的getline函数总结:

    来自:http://www.cnblogs.com/xFreedom/archive/2011/05/16/2048037.html C/C++中的getline函数总结 getline函数是一个比较 ...

随机推荐

  1. Ansible详解(一)

    简介 Ansible是一个简单的自动化运维管理工具,基于Python语言实现,由Paramiko和PyYAML两个关键模块构建,可用于自动化部署应用.配置.编排task(持续交付.无宕机更新等).主版 ...

  2. 卷积神经网络(CNN)模型结构

    在前面我们讲述了DNN的模型与前向反向传播算法.而在DNN大类中,卷积神经网络(Convolutional Neural Networks,以下简称CNN)是最为成功的DNN特例之一.CNN广泛的应用 ...

  3. 规范 : loading display & ui-view loading

    angular 没有compile 完成的接口,最像的接口是$viewContentLoaded(router ui),但是一开始会开始跑,因为有ui-view 暂时解决方法是在body的loadin ...

  4. 【转载】JavaScript继承详解一

    面向对象与基于对象 几乎每个开发人员都有面向对象语言(比如C++.C#.Java)的开发经验. 在传统面向对象的语言中,有两个非常重要的概念 - 类和实例. 类定义了一类事物公共的行为和方法:而实例则 ...

  5. python之数据库(mysql)操作

    前言: 最近开始学django了,学了下web框架,顿时感觉又会了好多知识.happy~~ 这篇博客整理写下数据库基本操作,内容挺少.明天写SQLAlchemy. 一.数据库基本操作 1. 想允许在数 ...

  6. [转载]解决win10 VC++6.0 应用程序无法正常运行 0xc0000142

    本文转载自http://blog.csdn.net/w_9449/article/details/52864135 转载请申明哦,其实我发现自从我在贴吧发了帖子后,就冒出了不少帖子.经验.当然方法和我 ...

  7. 徒手用Java来写个Web服务器和框架吧<第一章:NIO篇>

    因为有个不会存在大量连接的小的Web服务器需求,不至于用上重量级服务器,于是自己动手写一个服务器. 同时也提供了一个简单的Web框架.能够简单的使用了. 大体的需求包括 能够处理HTTP协议. 能够提 ...

  8. 3403: [Usaco2009 Open]Cow Line 直线上的牛

    3403: [Usaco2009 Open]Cow Line 直线上的牛 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 71  Solved: 62[S ...

  9. iOS性能之HTTP2.0

    在移动互联网领域蓬勃发展的今天,APP的性能也成为各大公司重点关注的方向,该系列文章主要针对iOS的性能的几个方面做一些研究. 什么是HTTP2.0? 网上很容易搜到关于HTTP2.0的概念的文章,这 ...

  10. 有关html,css,js,less的使用规范

    写前端写久了,规则跟着开发的项目走,突然觉得是不是该总结总结前端的语言使用规则,看到下面这篇还不错,就直接链接过来了哦 http://zhibimo.com/read/Ashu/front-end-s ...