2017-03-18 69 views
4

我有std::string问题..的std :: string停止在 0

问题是,'\0'被识别为字符串作为在类C的串的结束。

例如下面的代码:

#include <iostream> 
#include <string> 

int main() 
{ 
    std::string s ("String!\0 This is a string too!"); 
    std::cout << s.length(); // same result as with s.size() 
    std::cout << std::endl << s; 

    return 0; 
} 

输出这样的:

7 
String! 

这里有什么问题吗? std::string不应该与其他任何角色一样对待'\0'吗?

+3

为什么它是一个问题? – klutt

+0

因为C++字符串不应该是空终止(我认为),应该像对待任何其他字符 – galaxyworks

+0

是的,但是这并不回答我的问题。 :)为什么你在第一个字符串中有一个\ 0?无论如何,这不是一个可打印的字符。 – klutt

回答

7

想想看:如果你给出const char*,你将如何detemine,这里是一个真正的终止符0,并在那里被嵌入一个?

您需要可以明确地传递一个尺寸字符串,或从两个迭代器构造字符串

#include <string> 
#include <iostream> 


int main() 
{ 
    auto& str = "String!\0 This is a string too!"; 
    std::string s(std::begin(str), std::end(str)); 
    std::cout << s.size() << '\n' << s << '\n'; 
} 

例(指针):http://coliru.stacked-crooked.com/a/d42211b7199d458d

编辑:@ Rakete1111提醒我关于字符串文字:

using namespace std::literals::string_literals; 
auto str = "String!\0 This is a string too!"s; 
+3

为什么不使用字符串文字? 'auto str =“String!\ 0这也是一个字符串!”s;' – Rakete1111

+0

这个答案与我所寻找的最接近!谢谢:) – galaxyworks

+1

有趣的推论问题是为什么不重写'std :: string'构造函数来处理字符串文字来处理嵌入的空字符?从你的回答中可以清楚地看出,编译器本身显然对字符串结束位置没有什么困惑,否则'std :: end'也会给出错误的答案。只有在进入标准库时,信息才会被降级为一个简单的'const char *'并因此丢失。 – user4815162342

1

让您远离\ 0

std::string s ("String!\\0 This is a string too!"); 

,你会得到你所需要的:

31 
String!\0 This is a string too! 
+1

OP要他们的字符串包含一个NUL字符,而不是反斜杠后跟一个0. – chris

2

std::string实际上只有7个字符和终止'\0',因为这是你如何构建它。查看list of std::basic_string constructors:没有能够记住字符串文字大小的数组版本。在这里工作的一个是这样的一种:

basic_string(const CharT* s, 
       const Allocator& alloc = Allocator()); 

"String!\0 This is a string too!"char const[]阵列被转换为一个指向第一char元件。该指针被传递给构造函数,并且是所有的信息。为了确定字符串的大小,构造函数必须增加指针,直到找到第一个'\0'。这恰好是数组中的一个。


如果你碰巧有很多零个字节字符串的工作,然后有机会,std::vector<char>甚至std::vector<unsigned char>将是一个更自然的解决您的问题。

-1

这不是问题,那是预期的行为。

也许你可以详细说明为什么你的字符串中有\ 0。

使用std :: vector将允许您在字符串中使用\ 0。

+1

'std :: string'对字符串中的'\ 0''字节是很好的,不需要使用'std :: vector'就是因为它。 – hyde

1

\0被称为终止字符,因此您需要以某种方式跳过它。

String represntation

把它看作一个例子。

所以每当你想跳过特殊字符,你想用两个反斜线 “\\0

而且'\\0'是两个字符的文字

std::string test = "Test\\0 Test" 

结果:

Test\0 Test 

大多数初学者在加载时也会犯错,例如。文件:

std::ifstream some_file("\new_dir\test.txt"); //Wrong 
//You should be using it like this : 
std::ifstream some_file("\\new_dir\\test.txt"); //Correct 
+0

您的结果不匹配。这会产生'Test \ 0 Test'。 – chris

+0

关于你的文件示例:正确的方法是只写'/ new_dir/test.txt'。大多数Windows子系统在路径中正向斜杠的情况下工作得很好。 –

+0

@chris谢谢你,你是对的。对于那个很抱歉。 – lowarago

0

您正在从字符串文字构造std::string。字符串文字自动以'\0'终止。因此,一个字符串文字"f\0o"被编码为以下字符数组:

{'f', '\0', 'o', '\0'} 

string构造服用char const*将被调用,并且将实施这样的事:

string(char const* s) { 
    auto e = s; 
    while (*e != '\0') ++e; 

    m_length = e - s; 
    m_data = new char[m_length + 1]; 
    memcpy(m_data, s, m_length + 1); 
} 

显然,这ISN”技术上正确的实施,但你明白了。您手动插入的将被解释为字符串文字的结尾。

如果你想忽略额外'\0',你可以使用一个std::string文字:

#include <iostream> 
#include <string> 

int main() 
{ 
    using namespace std::string_literals; 

    std::string s("String!\0 This is a string too!"s); 
    std::cout << s.length(); // same result as with s.size() 
    std::cout << std::endl << s; 

    return 0; 
} 

输出:

30 
String! This is a string too! 
0

在极少数的话,你就构造你的C++字符串中的标准C字符串。

而标准的C字符串是零终止的。所以,你的C字符串参数将在它能够找到的第一个\0字符中被终止。并且该字符是您在字符串中明确提供的字符"String!\0 This is a string too!"

而不是在C标准字符串的末尾由编译器隐含并自动提供的第二个字符。