您的位置:首页 > 编程语言 > C语言/C++

c++ getline(),get()函数笔记

2016-05-04 15:30 751 查看
写这篇blog的起因在于:

function getline()在不指定休止符时,默认以换行作为休止符。

由于我的认识上的不足,一度认为

function cin.getline()的使用中将调用改函数之前的一个回车也进行了读取,导致数据转变的时候出错

可见于/article/10184135.html

的Row95和Row98。

后在vs2010中也做了如下的测试,发现直接输入回车后进行了换行输出。

char a[100];
memset(a,0,sizeof(a));
cin.getline(a,100);
cout<<"start"<<endl;
cout<<a<<endl;
cout<<"end"<<endl;


在调用std下的function getline()时也发生了同样的情况

string a;
getline(cin,a);
cout<<"start"<<endl;
cout<<a<<endl;
cout<<"end"<<endl;


解决方案:直接在getline()之前进行了调用了get(),将多余的回车吃掉。

分析部分:

istream中function getline()的实现:

_Myt& __CLR_OR_THIS_CALL getline(_Elem *_Str, streamsize _Count)
{   // get up to _Count characters into NTCS, discard newline
return (getline(_Str, _Count, _Myios::widen('/n')));
}


这里是两个参数的getline()的入口。

std::istream::getline

原型:

istream& getline (char* s, streamsize n );

istream& getline (char* s, streamsize n, char delim );

detail:http://www.cplusplus.com/reference/istream/istream/getline/

可以看到,在调用两个参数的getline时,实际上是函数为我们添加了第三个参数。

接下来调用了如下的函数:

_Myt& __CLR_OR_THIS_CALL 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 (_Ok && 0 < _Count)
{   // state okay, use facet to extract
int_type _Metadelim = _Traits::to_int_type(_Delim);
_TRY_IO_BEGIN
int_type _Meta = _Myios::rdbuf()->sgetc();// 从输入流读一个字符
for (; ; _Meta = _Myios::rdbuf()->snextc())
if (_Traits::eq_int_type(_Traits::eof(), _Meta))
{   // end of file, quit
_State |= ios_base::eofbit;// 遇到文件尾,getline结束
break;
}
else if (_Meta == _Metadelim)  //休止符的判断
{   // got a delimiter, discard it and quit
++_Chcount;
_Myios::rdbuf()->sbumpc();// 这句把结束符读掉了,如果不指定结束符,那就是把'/n'读掉了
break;
}// 遇到结束符,getline结束,注意这里的顺序,它是先判断是否遇到结束符,后判断是否读入了指定个数的。在这里计数器仍然执行++操作
else if (--_Count <= 0)
{   // buffer full, quit
_State |= ios_base::failbit;
break;
}// 读到了指定个数,执行到这里已经隐含了在指定个数的最后一位仍然不是结束符,由于在执行这部分时,在对长度计数器没有进行++操作
else
{   // got a character, add it to string
++_Chcount;
*_Str++ = _Traits::to_char_type(_Meta);
}
_CATCH_IO_END
}
*_Str = _Elem();    // add terminating null character
_Myios::setstate(_Chcount == 0 ? _State | ios_base::failbit : _State);
return (*this);
}


从实现当中我们可以看到,我之前的调用的确被正确执行了,当我直接输入回车时,getline()函数被调用,但有与第一个字符就是休止符,通过调用sbumpc()将指针指向了下一个字符后跳出循环,此时_Str当中什么都没有被存入,我们通过调用

*_Str = _Elem();    // add terminating null character


将_Str首位置为空字符’\0’。

接下来对_Str进行了输出,输出为空。

std::getline (string)

原型:

(1)

istream& getline (istream& is, string& str, char delim);

istream& getline (istream&& is, string& str, char delim);

(2)

istream& getline (istream& is, string& str);

istream& getline (istream&& is, string& str);

detail:http://www.cplusplus.com/reference/string/string/getline/

从输入流冲获取获取数据直到遇到delim休止符或文件结束符,将获得的数据放入到str当中,

关于读取到休止符的处理可以参考之前的_Myt& __CLR_OR_THIS_CALL getline()。

我们知道c++的string有类似vector的机制,会事先申请一个固定大小的空间,当空间不足时会重新申请一块更大的空间,将原来的数据复制进新的空间。

string a="fyb";
string b;
b=a;
a.push_back('b');
cout<<a<<endl;
cout<<&a<<endl;
cout<<b<<endl;
cout<<&b<<endl;


std::getline()实质就是每次将一个字符添加string的末尾,所以中间可能会存在内存空间的申请,和string数据的复制。

std::istream::get

原型:

single character (1)

int get();

istream& get (char& c);

c-string (2)

istream& get (char* s, streamsize n);

istream& get (char* s, streamsize n, char delim);

stream buffer (3)

istream& get (streambuf& sb);

istream& get (streambuf& sb, char delim);

detail:http://www.cplusplus.com/reference/istream/istream/get/

单字符的get可以进行逐字符地读入,类似getchar();

这里我们主要说的还是第二类,这里的应用跟getline及其类似,但get有一点需要注意,getline会将休止符一起读入后舍弃,但get遇到休止符就停止了,输入流队列当中仍然保留有休止符。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: