我昨天花了大约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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top