因為之前每次使用這個函數都要在網上查一遍,覺得很麻煩,這次就認真地整理一下,希望寫完之后就記住。
getline函數其實有兩個:
一個是全局函數,include<cstring>, 原型是 istream& getline( istream& is, string& str, char delim) 與 istream& getline( istream& is, string& str) , 得到的字符串存在一個string類型的str里。
另一個是iostream類的成員函數, include<iostream>, 原型是 istream& getline( char * str, streamsize n, char delim ) 與 istream& getline( char * str, streamsize n ) , 得到的字符串存在一個C-style字符數組str里。(值得注意的是,這個n應該小於字符數組str的長度,因為至少要留一個位置存放結束符'\0',后面這個還要探討一下)
以后可以參考的cin.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); //返回輸入流對象本身
}