STL基本字符串中的长度与空字符

8
为什么在std::basic_string中插入'\0'字符时,.length()方法不受影响,但如果调用char_traits<char>::length(str.c_str()),则会获得字符串长度直到第一个'\0'字符为止?
例如:
string str("abcdefgh");
cout << str.length(); // 8
str[4] = '\0';
cout << str.length(); // 8
cout << char_traits<char>::length(str.c_str()); // 4
1个回答

18

好问题!

原因是C风格的字符串定义为以空字节结尾的字节序列。当您使用.c_str()从C++ std::string中获取C风格字符串时,您会得到包含空字节的C++字符串存储序列。当您将此传递给strlen时,它将扫描字节直到遇到空字节,然后报告它在那之前找到了多少个字符。如果string包含一个空字节,那么strlen将报告比整个字符串长度小的值,因为它会在真正的字符串末尾之前停止。

一个重要细节是strlenchar_traits<char>::length不是同一个函数。然而,C++ ISO规范对于char_traits<charT>::length(§21.1.1)指出,char_traits<charT>::length(s)返回最小的i使得char_traits<charT>::eq(s[i], charT())为true。对于char_traits<char>eq函数只需通过执行==比较来返回两个字符是否相等,并通过写入char()来构造一个字符,从而产生一个空字节。因此,这等同于说“字符串中第一个空字节在哪里?” 这基本上就是strlen的工作原理,尽管两者在技术上是不同的函数。

C++的std::string是一个更一般性的“任意字符序列”的概念。它的具体实现细节对外部是隐藏的,但它可能是通过起始和停止指针或指针和长度来表示的。由于这种表示不依赖于存储的字符类型,所以询问std::string的长度将告诉您有多少个字符,而不管这些字符是什么。

希望这可以帮助您!


1
+1,我只想补充一下,如果你真的想要内部的空字节,我相信可以使用basic_string<>::data()成员函数。 - dappawit
6
@cappawit- 不是c_str()会去掉空字节,而是data()保留了它们;实际上,它们两个都有空字节,只不过c_str()保证末尾有一个空字节而data()没有。问题在于,那些内部字符串字节是如何被用于C风格字符串实现的函数解释的。 - templatetypedef
啊哈!你加了我正要放进答案里的那部分。 - Matt K
这让我想到了下一个问题,如果字符串类似乎并没有使用它,那么字符特征的意义是什么?(请勿在此回答) - Matthew Smith
@MattSmith- 请查看我对你其他问题的(长)回答。简短版是,std::string确实使用traits类,这为您提供了令人难以置信的灵活性。 - templatetypedef
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接