我测试了以下代码,以澄清我对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>>
之后,大小将会更改。任何人都可以帮我解析吗?
答案 0 :(得分:3)
两件事。
首先,>>
不占用空格,因此getline
会检索它。
其次,这条线不正确:
ss.getline(&s1[0], 250, '\n');
由于getline
需要std::basic_string
,只需传入字符串:
ss.getline(s1, 250, '\n');
在你的代码中,&s1[0]
可以访问写入的底层缓冲区,但是字符串的长度是单独存储的,并且仍然是前一次读取的内容(这就是为什么h
被删除了。但是,此时由于缓冲区溢出,您已经调用了未定义的行为。
答案 1 :(得分:3)
ss.getline(&s1[0], 250, '\n');
此getline()
来电的第一个参数是char *
。 ss
绝对不知道这个char
缓冲区实际上来自std::string
,它实际上是它的内部缓冲区。
使整个事件变得复杂的是,这std::string
的印象是它包含四个字符。因为这就是它的全部。
绝对没有什么可能导致这个std::string
改变主意。只是因为指向其内部字符缓冲区的指针被传递给getline()
,后者继续粗略地乱写它(导致未定义的行为,因为我将在片刻中推断),std::string
仍然认为它只包含四个字符。
同时,初始格式化输入操作符>>
提取了初始字符,但 没有 提取以下空格,所以当这个流后来,有了这个getline()
调用,它开始从这个空格字符开始提取字符的工作,直到下一个换行符 - 五个字符(如果我依靠我的手指),但将其转储到缓冲区中std::string
保证只能保留四个字符(因此,请记住,初始格式化的提取运算符>>
,只能在其中转储四个字符)。
我忽略了一些细节,例如std::string
负责自动处理尾随'\0'
,但底线是这是未定义的行为。 getline调用会提取更多字符,保证它所保留的缓冲区。未定义的行为。一大堆未定义的行为。不仅仅是你的第二行输出中的四个字符不是你期望看到的四个字符,只是getline()
实际上最终提取 更多 字符,但是在这里打印的std::string
在宪法下完全相信它仍然只有四个字符,只是它的内部缓冲区全部被踩了。