string.empty 和 string[0] == '\0' 之间的区别

Posted

技术标签:

【中文标题】string.empty 和 string[0] == \'\\0\' 之间的区别【英文标题】:Difference between string.empty and string[0] == '\0'string.empty 和 string[0] == '\0' 之间的区别 【发布时间】:2016-09-27 12:51:04 【问题描述】:

假设我们有一个字符串

std::string str; // some value is assigned

str.empty()str[0] == '\0' 有什么区别?

【问题讨论】:

std::string 不需要以 '\0' 结尾 @appleapple: str[str.size()] 始终是 '\0'(如下所述)。 是的,(c++11 起) 主要区别在于像std::string str"\0foo", 4这样的字符串。 std::string,与 C 风格的字符串不同,可能嵌入了 NUL。 【参考方案1】:

C++11 及更高版本

如果字符串为空,则需要string_variable[0] 返回空字符。这样就没有未定义的行为,如果字符串真的为空,比较仍然有效。但是,您可以有一个以空字符 ("\0Hi there") 开头的字符串,即使它不为空,它也会返回 true。如果你真的想知道它是否为空,请使用empty()


C++11 之前

不同之处在于,如果字符串为空,则string_variable[0] 具有未定义的行为;除非字符串是 const-qualified,否则没有索引 0。如果字符串 const 合格,那么它将返回一个空字符。

string_variable.empty() 如果字符串为空则返回 true,否则返回 false;行为不会是未定义的。


总结

empty() 用于检查字符串/容器是否为空。它适用于提供它的所有容器,并且使用 empty 清楚地表明了您的意图 - 这对阅读您的代码的人(包括您)来说意义重大。

【讨论】:

empty() 也适用于std::u16string,无需更改代码 您能否引用标准中的string[0] 可以在string.size() == 0 时进行引用?听起来很不是 C++ 是 这里只是吹毛求疵:Pre C++11,我认为如果字符串是 const 限定的,行为仍然是明确定义的,请参阅cplusplus.com/reference/string/string/operator[],引用:“如果 pos 等于字符串长度且字符串是 const 限定的,函数返回对空字符 ('\0') 的引用。" @NathanOliver:这就是为什么我说我在吹毛求疵;)。 (另外,我提到了 const 限定部分。) @LightnessRacesinOrbit:实际上,这是一个程序的特定执行,其行为要么已定义,要么未定义。 “未定义的行为”仅在程序的控制流通过其行为未定义的操作或构造时(而不是何时)触发。奇怪的是,该程序可能会在到达该点之前开始出现异常行为,但前提是它确实到达了那里。同一程序在不同输入上的另一次执行导致围绕有问题的操作的分支可以完美定义。【参考方案2】:

从 C++11 开始,保证str[str.size()] == '\0'。这意味着如果字符串为空,则为str[0] == '\0'。但是 C++ 字符串有一个明确的长度字段,这意味着它可以包含嵌入的空字符。

例如对于std::string str("\0ab", 3), str[0] == '\0'str.empty() 是假的。

此外,str.empty()str[0] == '\0' 更具可读性。

【讨论】:

我喜欢这个答案,因为它提到std::string 不是(必须)以空值终止。我认为。或者至少不是每个 null 都是它的终止符。 由于 cmets 已在没有通知的情况下被销毁,我不得不再说一遍(感谢那些家伙):@QPaysTaxes 只是为了让您和其他读者知道(您说“我认为”建议您不确定),您评论的正确部分是最后一部分。不是第一部分,这不是。 @Lightness 你以前的 cmets 非常模糊;我不知道你的“结束”是什么意思。这个版本更有帮助。谢谢!【参考方案3】:

这里的其他答案是 100% 正确的。我只想再补充三点:

empty 是通用的(每个 STL 容器都实现此功能),而 operator []size_t 仅适用于字符串对象和类似数组的容器。在处理通用 STL 代码时,首选empty

另外,empty 几乎是不言自明的,而 =='\0' 不是很多。 当凌晨 2 点调试代码时,您希望看到 if(str.empty()) 还是 if(str[0] == '\0')? 如果只有功能很重要,我们都会用 vanilla 程序集编写。

还涉及性能损失。 empty 通常是通过将字符串的大小成员与零进行比较来实现的,这非常便宜,易于内联等。与第一个字符进行比较可能会更重。首先,由于所有字符串都实现了短字符串优化,程序首先要询问字符串是处于“短模式”还是“长模式”。分支 - 性能更差。如果字符串很长,如果字符串被“忽略”了一段时间,取消引用可能代价高昂,并且取消引用本身可能会导致代价高昂的缓存错误。

【讨论】:

永远不要考虑在如此低的级别上进行优化,除非它实际上很慢。除非它在长时间运行的程序的内部循环中,否则性能并不重要。 (过早的优化是一种疾病,在 C/C++ 程序员恕我直言下更常见) - 另外:如果我明确寻找 \0/ 空 NULL 终止的字符串而不是空字符串对象,if(str[0] == '\0') 是完全有效的(是的,不太可能但可能)【参考方案4】:

empty() 没有实现为在位置 0 处寻找空字符的存在,它只是

bool empty() const

    return size() == 0 ;

可能不同

【讨论】:

【参考方案5】:

另外,如果您使用 C++ 11 或更高版本,请注意您将使用的函数:

#include <iostream>
#include <cstring>

int main() 
    std::string str("\0ab", 3);

    std::cout << "The size of str is " << str.size() << " bytes.\n";
    std::cout << "The size of str is " << str.length() << " long.\n";
    std::cout << "The size of str is " << std::strlen(str.c_str()) << " long.\n";

    return 0;

将返回

str 的大小为 3 个字节。

str的大小是3长。

str的大小为0 long。

【讨论】:

【参考方案6】:

您想知道str.empty() and str[0] == '\0' 之间的区别。让我们按照例子:

#include<iostream>
#include<string>
using namespace std;

int main()
string str, str2; //both string is empty
str2 = "values"; //assigning a value to 'str2' string
str2[0] = '\0'; //assigning '\0' to str2[0], to make sure i have '\0' at 0 index

if(str.empty()) cout << "str is empty" << endl;
else cout << "str contains: " << str << endl;

if(str2.empty()) cout << "str2 is empty" << endl;
else cout << "str2 contains: " << str2 << endl;

return 0;

输出:

str is empty
str2 contains: alues

str.empty() 会让你知道字符串是否为空,str[0] == '\0' 会让你知道你的字符串 0 索引是否包含'\0'。您的字符串变量 0 索引包含 '\0' 并不意味着您的字符串为空。是的,只有当您的字符串长度为 1 并且您的字符串变量 0 索引包含 '\0' 时才有可能。那个时候你可以这么说,它是一个空字符串。

【讨论】:

【参考方案7】:

C++字符串有是否为空的概念。如果字符串为空,则 str[0] 未定义。仅当 C++ 字符串的大小 >1 时,才定义 str[0]。

str[i] == '\0' 是 C-string 风格的概念。在C字符串的实现中,字符串的最后一个字符是'\0'来标记一个C字符串的结束。 对于 C 字符串,您通常必须使用单独的变量“记住”字符串的长度。在 C++ 字符串中,您可以使用 '\0' 分配任何位置。

只是一个可以玩的代码段:

#include <iostream>
#include <string>

using namespace std;

int main(int argc, char* argv[]) 
   char str[5] = "abc";
   cout << str << " length: " << strlen(str) << endl;
   cout << "char at 4th position: " << str[3] << "|" << endl;
   cout << "char at 5th position: " << str[4] << "|" << endl;
   str[4]='X'; // this is OK, since Cstring is just an array of char!
   cout << "char at 5th position after assignment: " << str[4] << "|" << endl;
   string cppstr("abc");
   cppstr.resize(3);
   cout << "cppstr: " << cppstr << " length: " << cppstr.length() << endl;
   cout << "char at 4th position:" << cppstr[3] << endl;
   cout << "char at 401th positon:" << cppstr[400] << endl;
   // you should be getting segmentation fault in the
   // above two lines! But this may not happen every time.

   cppstr[0] = '\0';
   str[0] = '\0';
   cout << "After zero the first char. Cstring: " << str << " length: " << strlen(str) << " | C++String: " << cppstr << " length: " << cppstr.length() << endl;
   return 0;

在我的机器上输出:

abc length: 3
char at 4th position: |
char at 5th position: |
char at 5th position after assignment: X|
cppstr: abc length: 3
char at 4th position:
char at 401th positon:?
After zero the first char. Cstring:  length: 0 | C++String: bc length: 3

【讨论】:

以上是关于string.empty 和 string[0] == '\0' 之间的区别的主要内容,如果未能解决你的问题,请参考以下文章

C# string总结

C# string总结

string、Empty和null三者的区别

王立平--string.Empty

如果有 string.Empty 为啥没有 char.Empty? [复制]

C++:string.empty() 是不是总是等价于 string == ""?