提问人:Finley 提问时间:1/24/2018 最后编辑:Finley 更新时间:1/24/2018 访问量:71
令人费解的 istream::getline() 行为
Puzzling behavior of istream::getline()
问:
我测试了以下代码以澄清我的理解: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
此外,我发现通话后的大小与通话后的大小相同,但再次通话后大小会改变。谁能帮我解析?s1
ss.getline()
ss>>
ss>>
答:
两件事。
首先,不占用空格,因此会检索它。>>
getline
其次,这条线不正确:
ss.getline(&s1[0], 250, '\n');
由于需要 ,只需传入字符串:getline
std::basic_string
ss.getline(s1, 250, '\n');
在代码中,获取对基础缓冲区的访问权限,该缓冲区被写入,但字符串的长度是单独存储的,并且仍然是上一次读取的长度(这就是删除的原因)。不过,此时您已经由于缓冲区溢出而调用了未定义的行为。&s1[0]
h
评论
getline
std::string
istream
s 的 getline
成员函数实际上并不处理 ,只有 。您需要使用 std::getline
函数,例如 (注意:它不采用大小,因为它会根据需要调整基础字符串的大小)。std::string
char*
std::getline(ss, s1, '\n');
ss.getline(&s1[0], 250, '\n');
此调用的第一个参数是 . 完全不知道这个缓冲区实际上来自一个 ,它实际上是它的内部缓冲区。getline()
char *
ss
char
std::string
使整个事件复杂化的事实是,这给人的印象是它包含四个字符。因为在这一点上,这就是它的全部。std::string
绝对没有任何事情可能导致它改变主意。仅仅因为指向其内部字符缓冲区的指针被传递给 ,它继续相当粗鲁地在其上乱涂乱画(导致未定义的行为,我稍后会推断),仍然认为它只包含四个字符。std::string
getline()
std::string
同时,初始格式化的输入运算符提取了初始字符,但没有提取以下空格,因此当这个流随后进行此调用时,它开始提取从这个空格字符开始的字符,直到下一个换行符 -- 五个字符(如果我指望我的手指),但将其转储到一个有保证的缓冲区中, 通过 ,长度仅足以容纳四个字符(因为,请记住,初始格式化的提取运算符 ,只在其中转储了四个字符)。>>
getline()
std::string
>>
我忽略了一些细节,例如负责自动跟踪的事实,但底线是这是未定义的行为。getline 调用提取更多字符,它所提供的缓冲区保证可以保存这些字符。未定义的行为。一大堆未定义的行为。不仅仅是你第二行输出中的四个字符不是你期望看到的四个字符,只是实际上最终提取了更多的字符,但这里打印的完全有权相信它仍然只有四个字符,只是它的内部缓冲区被踩了一脚。std::string
'\0'
getline()
std::string
评论
ss.getline(&s1[0], 250, '\n');
导致缓冲区溢出,您将 5 个字符(+ 终止符)读入仅大小为 4 的字符串中std::stringstream::getline()
std::string
std::getline()
std::getline(ss, s1, '\n');