在我的印象中,getline函数常常出如今自己的视野里,模糊地记得它常常常使用来读取字符串

。可是又对它的參数不是非常了解,今天又用到了getline函数,如今来细细地总结一下:

首先要明确设计getline函数的目的,事实上非常easy,就是从流中读取字符串。并且读取的方

式有非常多,包含依据限定符,依据已读取的字符的个数。从这个函数的名称来看,它的直观

意义是从流中读取一行,可是大家不要被这表面的现象所迷惑。事实上假设让我来为这个函数

去一个名字的话,也许我会取一个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’留

下一个位置。其它地方二者基本同样。

原理想必也非常easy。每一次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. getline函数彻底说明

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

  2. getline()函数

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

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

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

  4. C++: getline函数

    转自http://blog.sina.com.cn/s/blog_60263c1c0101ck25.html 学习C++的同学可能都会遇到一个getline()函数,譬如在C++premer中,标准s ...

  5. C++学习46 getline()函数读入一行字符 一些与输入有关的istream类成员函数

    getline函数的作用是从输入流中读取一行字符,其用法与带3个参数的get函数类似.即    cin.getline(字符数组(或字符指针), 字符个数n, 终止标志字符) [例13.7] 用get ...

  6. c程序设计语言_习题1-16_自己编写getline()函数,接收整行字符串,并完整输出

    Revise the main routine of the longest-line program so it will correctly print the length of arbitra ...

  7. Linux下的getline函数

    最近在做国嵌的mp3项目,在mp3主控程序中用到了这个函数,挺好使的,在这里记录一下.注意是linux下的,不是C++中的. 函数原型 ssize_t getline(char **lineptr, ...

  8. C++中getline函数的使用

    代码: #include <iostream> #include <cstdio> using namespace std; int main(){ char* s; s = ...

  9. getline函数(精华版)

    在我的印象中,getline函数经常出现在自己的视野里,模糊地记得它经常用来读取字符串   .但是又对它的参数不是很了解,今天又用到了getline函数,现在来细细地总结一下:   首先要明白设计ge ...

随机推荐

  1. 关于arguments.callee的用途

    arguments为js函数中两个隐藏属性中的一个(另一个为this) arguments表示所有传入的参数,为类数组(array-like)类型,arguments.length表示传入参数的长度, ...

  2. C语言如何定义结构体

    原文地址 1. struct与typedef struct区别 struct是结构体的关键字,用来声明结构体变量如 struct  student {   char  num[10];      ch ...

  3. Linux常用命令--网络管理篇(三)

    ping –b 10.0.0.255 扫描子网网段 ifconfig 查看网络信息 netconfig 配置网络,配置网络后用service network restart重新启动网络 ifconfi ...

  4. SQL Server 恢复过程

    在恢复过程中.只会分析那些自最后一个检查点之后发生的更改,以确定是否需要重做还是撤销. 在最后一个检查点之前完成的操作都会精确的反应到数据文件中,恢复过程不需要做其它的事. 第一阶段: 分析. 这个阶 ...

  5. Referrer 还是 Referer?

    上回我写了一篇文章介绍「Referrer Policy」,有小伙伴看完后问我:Referrer 这个单词到底怎么拼,为什么有时候中间有两个 r,有时候只有一个? 是的,这是一个很有趣的问题,这里就给有 ...

  6. 有哪些适合学生参与的 C++,网络编程方面的开源项目?

    有哪些适合学生参与的 C++,网络编程方面的开源项目?   Tinyhttpd是一个超轻量型Http Server,使用C语言开发,全部代码只有502行(包括注释),附带一个简单的Client,可以通 ...

  7. UberX及以上级别车奖励政策(优步北京第四组)

    优步北京第四组: 定义为2015年7月20日至今激活的司机(以优步后台数据显示为准) 滴滴快车单单2.5倍,注册地址:http://www.udache.com/如何注册Uber司机(全国版最新最详细 ...

  8. 开发者工具console

    **(2)$0 - $4 ** 控制台保存了最近5个在Elements面板选中的DOM元素,$0代表倒数第一个,$1代表倒数第二个,以此类推直到$4. 按f12,就会出现开发者工具,然后在左上角有个放 ...

  9. iOS 导航条的影响

    如果是push出来的控制器,self.view的(0,0)点从状态栏下面开始: 如果有present出来的控制器,self.view的(0,0)点包含状态栏:

  10. cocostudio导出plist文件

    今天在用Armature类时用到cocostudio导出文件,由于美术的原因他使用的是中文命名法(这你敢相信),后面在导入程序中跟了下代码发现是解析plist文件有误,我就来比较正常功能文件和有错文件 ...