题
我昨天花了大约4个小时试图在我的代码中解决这个问题。我将问题简化为以下示例。
这个想法是将字符串存储在以std :: ends结尾的字符串流中,然后稍后检索它并将其与原始字符串进行比较。
#include <sstream> #include <iostream> #include <string> int main( int argc, char** argv ) { const std::string HELLO( "hello" ); std::stringstream testStream; testStream << HELLO << std::ends; std::string hi = testStream.str(); if( HELLO == hi ) { std::cout << HELLO << "==" << hi << std::endl; } return 0; }
正如您可能猜到的,执行上述代码时不会打印任何内容。
虽然,如果打印出来,或者在调试器(VS2005)中查看,HELLO和hi看起来相同,他们的.length()实际上相差1.这就是我猜的是导致“==”操作员失败。
我的问题是为什么。我不明白为什么std :: ends是一个不可见的字符添加到字符串hi,使hi和HELLO的长度不同,即使它们具有相同的内容。此外,这个看不见的角色不会被增强修剪修剪。但是,如果使用strcmp比较两个字符串的.c_str(),则比较正常。
我首先使用std :: ends的原因是因为我在过去遇到了一些问题,因为stringstream在流的末尾保留了垃圾数据。 std :: ends为我解决了这个问题。
解决方案
std :: ends
在流中插入一个空字符。将内容作为 std :: string
获取将保留该空字符,并在相应位置创建一个具有该空字符的字符串。
所以std :: string确实可以包含嵌入的空字符。以下std :: string内容 不同:
ABC
ABC\0
二进制零不是空格。但它也不能打印,所以你不会看到它(除非你的终端专门显示它)。
使用 strcmp
进行比较,当您传递 .c_str()
时,会将 std :: string
的内容解释为C字符串。它会说
嗯,第一个
\ 0
(终止空字符)之前的字符是 ABC ,所以我认为字符串是 ABC
因此,上述两者之间不会有任何区别。您可能遇到此问题:
std::stringstream s;
s << "hello";
s.seekp(0);
s << "b";
assert(s.str() == "b"); // will fail!
断言将失败,因为stringstream使用的序列仍然是包含“hello”的旧序列。你做的只是覆盖第一个角色。你想这样做:
std::stringstream s;
s << "hello";
s.str(""); // reset the sequence
s << "b";
assert(s.str() == "b"); // will succeed!
另请阅读以下答案:如何重用ostringstream
其他提示
std :: ends
只是一个空字符。传统上,C和C ++中的字符串以null(ascii 0)字符终止,但事实证明 std :: string
并不真正需要这个东西。无论如何,我们逐点逐步完成您的代码,我们会看到一些有趣的事情:
int main( int argc, char** argv )
{
字符串文字&quot; hello&quot;
是传统的零终止字符串常量。我们将整个复制到 std :: string
HELLO。
const std::string HELLO( "hello" );
std::stringstream testStream;
我们现在将 string
HELLO(包括尾随0)放入 stream
,然后是第二个null,通过调用 std放在那里::端代码>
testStream << HELLO << std::ends;
我们提取出我们放入 stream
(文字字符串“hello”,加上两个空终止符)的东西的副本。
std::string hi = testStream.str();
然后我们使用 std :: string
类上的 operator ==
比较两个字符串。此运算符(可能)比较 string
对象的长度 - 包括多少尾随空字符。请注意, std :: string
类不要求底层字符数组以尾随空格结尾 - 换句话说它允许字符串包含空字符,因此两个尾随空字符中的第一个是作为字符串 hi
的一部分处理。
由于两个字符串的尾随空值数不同,因此比较失败。
if( HELLO == hi )
{
std::cout << HELLO << "==" << hi << std::endl;
}
return 0;
}
虽然,如果打印出来,或者看着 在调试器(VS2005)中,HELLO和嗨 看起来相同,他们的.length()in 事实相差1.这就是我 猜测导致“==”操作者 失败。
原因是,长度因尾随空字符而不同。
我的问题是为什么。我不 理解为什么std :: ends是一个 不可见的字符添加到字符串 嗨,喜欢和你好不同 即使他们有长度 相同的内容。而且,这个 看不见的角色没有得到 用增强装饰修剪。但是,如果 你使用strcmp来比较.c_str() 两个字符串,比较工作 正确。
strcmp
与 std :: string
不同 - 它是在早期以字符串以null结尾的时候写的 - 所以当它到达第一个在 hi
中尾随null,它停止查找。
我使用std ::的原因结束了 第一名是因为我遇到了问题 在过去使用stringstream 保留垃圾数据 流。 std :: ends解决了这个问题 我
有时理解底层表示是个好主意。
您正在使用std :: ends向HELLO添加NULL char。使用str()初始化hi时,您将删除NULL char。字符串是不同的。 strcmp不比较std :: strings,它比较char *(它是一个C函数)。
std :: ends添加一个空终止符,(char)'\ 0'。您将它与已弃用的strstream类一起使用,以添加null终止符。
你不需要使用stringstream,事实上它搞砸了,因为空终止符不是“结束字符串的特殊空终结符”。串流,串流它只是另一个角色,第0个角色。 stringstream只是添加它,并且将字符数(在您的情况下)增加到7,并将比较与“hello”相对应。失败。
我认为有一个比较字符串的好方法是使用 std :: find
方法。不要混用C方法和 std :: string ones
!