令人费解的 istream::getline() 行为

Puzzling behavior of istream::getline()

提问人:Finley 提问时间:1/24/2018 最后编辑:Finley 更新时间:1/24/2018 访问量:71

问:

我测试了以下代码以澄清我的理解:istream::getline()

 #include <iostream>
    #include <sstream>
    using namespace std;
        int main()    
        {
           string s("abcd efgh\nijklmnopqrst");         
           string s1;
           stringstream ss(s);
           ss >> s1;
           cout << s1 << endl;
           ss.getline(&s1[0], 250, '\n');
           cout << s1 << endl;
           ss >> s1;
           cout << s1 << endl;
           getchar();
        return 1;
        }

然后控制台打印:

abcd
 efg
ijklmnopqrst

但在我看来,它应该是

abcd
efgh
ijklmnopqrst

此外,我发现通话后的大小与通话后的大小相同,但再次通话后大小会改变。谁能帮我解析?s1ss.getline()ss>>ss>>

C++ IOstream 获取线

评论

1赞 M.M 1/24/2018
ss.getline(&s1[0], 250, '\n');导致缓冲区溢出,您将 5 个字符(+ 终止符)读入仅大小为 4 的字符串中
0赞 Justin Randall 1/24/2018
由于不支持,我更喜欢使用与字符串配合得很好。std::stringstream::getline()std::stringstd::getline()std::getline(ss, s1, '\n');

答:

3赞 Ken Wayne VanderLinde 1/24/2018 #1

两件事。

首先,不占用空格,因此会检索它。>>getline

其次,这条线不正确:

ss.getline(&s1[0], 250, '\n');

由于需要 ,只需传入字符串:getlinestd::basic_string

ss.getline(s1, 250, '\n');

在代码中,获取对基础缓冲区的访问权限,该缓冲区被写入,但字符串的长度是单独存储的,并且仍然是上一次读取的长度(这就是删除的原因)。不过,此时您已经由于缓冲区溢出而调用了未定义的行为。&s1[0]h

评论

0赞 Ben Voigt 1/24/2018
成员函数不能使用 .但是,有一个免费功能可以。getlinestd::string
1赞 ShadowRanger 1/24/2018
istreams 的 getline 成员函数实际上并不处理 ,只有 。您需要使用 std::getline 函数,例如 (注意:它不采用大小,因为它会根据需要调整基础字符串的大小)。std::stringchar*std::getline(ss, s1, '\n');
0赞 Ken Wayne VanderLinde 1/24/2018
谢谢,我确实在考虑非会员功能。
3赞 Sam Varshavchik 1/24/2018 #2
ss.getline(&s1[0], 250, '\n');

此调用的第一个参数是 . 完全不知道这个缓冲区实际上来自一个 ,它实际上是它的内部缓冲区。getline()char *sscharstd::string

使整个事件复杂化的事实是,这给人的印象是它包含四个字符。因为在这一点上,这就是它的全部。std::string

绝对没有任何事情可能导致它改变主意。仅仅因为指向其内部字符缓冲区的指针被传递给 ,它继续相当粗鲁地在其上乱涂乱画(导致未定义的行为,我稍后会推断),仍然认为它只包含四个字符。std::stringgetline()std::string

同时,初始格式化的输入运算符提取了初始字符,但没有提取以下空格,因此当这个流随后进行此调用时,它开始提取从这个空格字符开始的字符,直到下一个换行符 -- 五个字符(如果我指望我的手指),但将其转储到一个有保证的缓冲区中, 通过 ,长度仅足以容纳四个字符(因为,请记住,初始格式化的提取运算符 ,只在其中转储了四个字符)。>>getline()std::string>>

我忽略了一些细节,例如负责自动跟踪的事实,但底线是这是未定义的行为。getline 调用提取更多字符,它所提供的缓冲区保证可以保存这些字符。未定义的行为。一大堆未定义的行为。不仅仅是你第二行输出中的四个字符不是你期望看到的四个字符,只是实际上最终提取了更多的字符,但这里打印的完全有权相信它仍然只有四个字符,只是它的内部缓冲区被踩了一脚。std::string'\0'getline()std::string