一手资料详解C++中的getline函数

在刷OJ时,难免会遇到要读入一行含有空格的字符串,这时C++中的getline便大显身手了。但是每次要用getline都心里打鼓,不知道换行符该不该使用getchar()读走。今晚又被网上的博客坑了,索性到http://www.cplusplus.com找一手资料去理解。

先给结论

  1. 重载运算符>>遇到空格或者换行符结束,但是输入结束后,换行符或空格本身还在流中。

  2. <string>中不指定分隔符的getline函数(重载版本2)遇到换行符结束,并将原来字符串中的内容清空,替换成新输入的字符串。

  3. <string>中如果在getline函数(重载版本1)中指定了分隔符,那么遇到换行符的时候会将换行符也读入到字符串中,也就是说可以读入多行,直到遇到指定的分隔符,并将分隔符从流中取出并丢弃。

  4. 如果使用cin输入后,紧跟着要用getline读入,就必须使用getchar()将流中的换行符读走。否则,getline会将原来字符串中的内容清空,然后读到了cin输入结束后的换行符,将换行符从流中提取出来并丢弃,输入也随之结束,这样,原来的字符串不仅不能被写入新的内容,反而连原来的内容也丢失了,变成了一个空串。

0.C++中的getline们

C++有两个头文件中实现了getline函数。一个在<string>中,一个在<iostream>中,这个函数从流中向string型字符串中写字符。

第一种往往使用getline(cin , str)的形式调用,第二种则采用cin.getline(arr, length)的形式调用,这个函数从流中想C风格的字符串中写字符。

1.std::getline (string)

1.1.概述及官网文档

截图来源:http://www.cplusplus.com/reference/string/string/getline/

可以看到,这个头文件中的getline方法,C++98和C++11有所不同,这里只介绍C++11的版本。

1.2 对英文文档的翻译 

 从流中读取一行到string字符串中

从输入流参数is中提取字符,并将这些字符存储到string型参数str中,直到读到了分隔符delim(对重载版本(2)来说,直到读到了换行符,'\n')

如果读到了文件结尾标志(EOF,在Windows下使用Ctrl+Z输入该符号,Linux下一般使用Ctrl+D),或者在输入过程中出现了一些其他错误,从流中提取取字符的操作也会停止。

如果在读取的过程中发现了分隔符,它会从流中被提取出来,并丢弃。(也就是说,分隔符不会被存储到字符串中,并且下次会从分隔符后面的字符开始向字符串中读入)

注意str中的所有内容会被新提取出来的字符序列所替换。

每一个从流中提取出来的字符串会被追加到这个string型的字符串中,好像是调用了string的成员函数push_back

参数的说明

is

      一个输入流istream的对象,所有存入字符串中的字符都从这个流中提取。(从键盘读直接写cin就行。)

str

      一个string对象,从流中提取出来的一行字符串将会存储到str中。在调用getline函数之前存储在str中的内容(如                   果有的话)将会被丢弃,并用从is中提取出来的字符串所代替。

1.3 实验代码(有注释)

1.3.1 对重载版本(1)的实验

(1)
istream& getline (istream&  is, string& str, char delim);
istream& getline (istream&& is, string& str, char delim);//二重引用没研究

 实验代码:

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string str[2];
    for(int i = 0; i < 2; i++)
        getline(cin, str[i], '*');//使用‘*’作为分隔符

    cout << "str 0:" << endl << str[0] << endl;
    cout << "str 1:" << endl << str[1];
}

输入样例:

111
111
*
222
222
333* 

输出样例:

str 0:
111
111

str 1:

222
222
333

分析:

使用分割符的getline()函数遇到换行符并不会结束,而是将换行符也读入到字符串中,直到遇到指定的分隔符。 然后从流中将分隔符提取出来并丢弃。

1.3.2 对重载版本(2)的实验

这个函数应该在刷OJ时最常用的。使用换行符结束要读入的一行字符串。

(2)
istream& getline (istream&  is, string& str);
istream& getline (istream&& is, string& str);//二重引用没研究

实验代码:

#include <iostream>
#include <string>

using namespace std;

int main()
{
    string str[4];

    cout << "please input 4 lines:" << endl;
    for(int i = 0; i < 2; i++)//先对数组中前两个字符串进行读入
    {   //注意并没有使用getchar()读走换行符
        getline(cin, str[i]);
    }

    for(int i = 2; i < 4; i++)//再对后两个字符串进行读入
    {   //试图用getchar()读走换行符
        getchar();
        getline(cin, str[i]);
    }

    cout << endl << "out:" << endl;
    for(int i = 0; i < 4; i++)
    {
        cout << str[i] << endl;
    }
    return 0;
}

 输入样例:

How are you?
I'm fine, thanks.
Emm...Would you like to date with me?
Emm...What's the matter with you?

输出样例:

How are you?
I'm fine, thanks.
mm...Would you like to date with me?
mm...What's the matter with you?

仔细看,第三行的字符串和第四行的字符串,由于getline()提取流中的换行符并丢弃,在试图使用getchar()读取换行符时,就会读走流中的第一个字符,在这个例子中,getchar()读走了流中的字符‘E’,所以有了上面的输出结果。

 

2.std::istream::getline

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

Get line 

获得一行

Extracts characters from the stream as unformatted input and stores them into s as a c-string, until either the extracted character is the delimiting character, or n characters have been written to s (including the terminating null character).
从流中提取字符串,作为未格式化的输入并且将这些字符作为C风格的字符串存储到S中,直到从流中提取到的字符是分隔符,或者已经有n个字符被写入到了s中(包括表示结尾的null字符)。
The delimiting character is the newline character ('\n') for the first form, and delim for the second: when found in the input sequence, it is extracted from the input sequence, but discarded and not written to s.
对第一种形式来说,分隔符是换行符('\n'),对第二种形式来说,当在输入流中发现了指定的分隔符后,它会被从流中提取出来,但是会被丢弃掉,不会写入到s中。
The function will also stop extracting characters if the end-of-file is reached. If this is reached prematurely (before either writing n characters or finding delim), the function sets the eofbit flag.
如果读到了end-of-file符号,这个函数也会停止从流中提取字符。如果 文件分隔符被提前读到(在写够n个字符之前或者发现分隔符),这个函数会设置eofbit标志。
The failbit flag is set if the function extracts no characters, or if the delimiting character is not found once (n-1)characters have already been written to s. Note that if the character that follows those (n-1) characters in the input sequence is precisely the delimiting character, it is also extracted and the failbit flag is not set (the extracted sequence was exactly n characters long).
如果没有提取到字符串,或者向s中写入了(n-1)个字符之后还没有发现分隔符,这个函数会设置failbit标志。注意,如果如果输入流中这(n-1)个字符之后紧跟着就是分隔符,它也会被提取出来而且failbit标志位不会被设置(提取出来的字符序列长度刚好是n个字符)
null character ('\0') is automatically appended to the written sequence if n is greater than zero, even if an empty string is extracted.
如果n大于0,一个空字符('\0')会被自动地追加到被写入序列中,即使被提取出来的是一个空字符串。
Internally, the function accesses the input sequence by first constructing a sentry object (with noskipws set to true). Then (if good), it extracts characters from its associated stream buffer object as if calling its member functions sbumpc or sgetc, and finally destroys the sentry object before returning.
这句话没搞太懂,但是www.cplusplus.com没法访问了,有机会再写。
The number of characters successfully read and stored by this function can be accessed by calling member gcount.

This function is overloaded for string objects in header <string>: See getline(string).

猜你喜欢

转载自blog.csdn.net/qq_38127801/article/details/86319726