我昨天花了大约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为我解决了这个问题。
答案 0 :(得分:11)
std::ends
在流中插入一个空字符。将内容作为std::string
保留将保留该空字符,并在相应位置创建一个具有该空字符的字符串。
所以std :: string确实可以包含嵌入的空字符。以下std :: string内容 不同:
ABC
ABC\0
二进制零不是空格。但它也不能打印,所以你不会看到它(除非你的终端专门显示它)。
使用strcmp
进行比较会在您传递std::string
时将.c_str()
的内容解释为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!
另请阅读此答案:How to reuse an ostringstream
答案 1 :(得分:4)
std::ends
只是一个空字符。传统上,C和C ++中的字符串以null(ascii 0)字符终止,但事实证明std::string
并不真正需要这个东西。无论如何,我们逐点逐步完成您的代码,我们会看到一些有趣的事情:
int main( int argc, char** argv )
{
字符串文字"hello"
是传统的零终止字符串常量。我们将整个复制到std::string
HELLO。
const std::string HELLO( "hello" );
std::stringstream testStream;
我们现在将string
HELLO(包括尾随0)放入stream
,然后是第二个空值,通过调用std::ends
放置。
testStream << HELLO << std::ends;
我们提取出我们放入stream
的内容的副本(文字字符串“hello”,加上两个空终止符)。
std::string hi = testStream.str();
然后我们使用operator ==
类上的std::string
比较两个字符串。此运算符(可能)比较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
中的第一个尾随空值时停止寻找。
我使用std ::的原因结束了 第一名是因为我遇到了问题 在过去使用stringstream 保留垃圾数据 流。 std :: ends解决了这个问题 我
有时理解底层表示是个好主意。
答案 2 :(得分:0)
您正在使用std :: ends向HELLO添加NULL char。使用str()初始化hi时,您将删除NULL char。字符串是不同的。 strcmp不比较std :: strings,它比较char *(它是一个C函数)。
答案 3 :(得分:0)
std :: ends添加一个空终止符,(char)'\ 0'。您将它与已弃用的strstream类一起使用,以添加null终止符。
你不需要使用stringstream,事实上它搞砸了,因为null终止符不是“结束字符串的特殊空终结符”到字符串流,字符串流它只是另一个字符,第0个字符。 stringstream只是添加它,并且会将字符数(在您的情况下)增加到7,并使比较为“hello”失败。
答案 4 :(得分:0)
我认为有一种比较字符串的好方法是使用std::find
方法。不要混用C方法和std::string ones
!