字符串.empty和字符串[0] == '\0'的区别

66

假设我们有一个字符串

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

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


8
std::string 不需要以 '\0' 结尾。 - apple apple
5
str[str.size()] 总是 '\0' (如下所讨论)。 - Lightness Races in Orbit
是的,(自C++11起) - apple apple
11
主要区别在于像std::string str{"\0foo", 4}这样的字符串中。与C风格的字符串不同,std::string可以包含嵌入式的NUL字符。 - Tavian Barnes
7个回答

92

C++11及以后版本

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


C++11之前版本

区别在于,如果字符串是空的,则string_variable[0]具有未定义的行为;除非该字符串是const限定的,否则不存在索引0。如果该字符串被const修饰,那么它将返回一个空字符。

string_variable.empty()则在字符串为空时返回true,在不为空时返回false。这种行为不会产生未定义的结果。


总结

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


14
empty() 也能在不需要改变代码的情况下与 std::u16string 一起使用。 - Panagiotis Kanavos
1
你能引用标准来证明当 string.size() == 0 时,string[0] 是合法的吗?这听起来非常不像 C++。 - David Haim
1
@NathanOliver:这就是我为什么说我在吹毛求疵的原因;)。(另外,我提到了const限定部分。) - rainer
2
@LightnessRacesinOrbit:实际上,它是程序的特定执行,其行为要么被定义,要么未定义。只有当程序的控制流通过其行为未定义的操作或结构时,“未定义行为”才会被触发。奇怪的是,程序在到达该点之前就可能开始出现问题,但前提是它确实到达了那里。对于不同输入导致绕过有问题操作的分支的同一程序的另一个执行可以是完全定义的。 - Ben Voigt
@BenVoigt 但我认为如果存在任何具有未定义行为的有效输入执行,则可以合理地说“程序的行为是未定义的”。 - Lii
显示剩余16条评论

38
自从C++11标准,保证 str[str.size()] == '\0' ,也就是说,如果一个字符串为空,则 str[0] == '\0'。但是,C++字符串具有显式长度字段,这意味着它可以包含嵌入的空字符。
例如对于 std::string str("\0ab", 3)str[0] == '\0',但是str.empty()为false。
此外,str.empty()str[0] == '\0' 更易读。

我喜欢这个答案,因为它提到std::string并不需要以 null 结尾。至少不是每一个 null 都是其终止符。 - anon
3
由于没有通知就删除了评论,我必须再次说一遍(感谢你们这些人):@QPaysTaxes 为了让你和其他读者知道(你说“我认为”这意味着你不确定),你评论中正确的部分是最后一部分,而不是第一部分,它是错误的。 - Lightness Races in Orbit
1
@Lightness,你之前的评论非常含糊,我无法确定你所说的“结束”是指什么。这个版本更加有帮助。谢谢! - anon

23

这里的其他答案都是100%正确的。我只想再添加三点说明:

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

而且,empty相当明确易懂,而=='\0'则不然。 当你在凌晨2点调试代码时,你更喜欢看到if(str.empty())还是if(str[0] == '\0')? 如果只考虑功能,我们都将使用纯汇编语言来编写。

此外,还涉及性能损失问题。empty通常通过将字符串的大小成员与零进行比较来实现,这非常便宜、易于内联等。而对比第一个字符可能会更消耗资源。首先,由于所有字符串都实现了短字符串优化,程序必须首先询问字符串处于“短模式”还是“长模式”。分支-性能更差。如果字符串很长,解引用它可能是昂贵的,特别是如果该字符串已被“忽略”一段时间且解引用本身可能会导致缓存故障,这也是代价高昂的。


除非实际上很慢,否则不要在这么低的层次上考虑优化。性能只有在长时间运行的程序的最内部循环中才重要。(过早的优化是一种疾病,在C/C++程序员中更为频繁)- 另外:如果我明确寻找\0/空的NULL结尾字符串而不是空字符串对象(是的,不太可能但有可能),那么if(str[0] == '\0')是完全有效的。 - Peter Schneider

6

empty()方法并不是通过查找位置0处是否存在空字符来实现的,它只是

bool empty() const
{
    return size() == 0 ;
}

这可能是不同的情况


4

另外,如果您使用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个长整型。


3
你想知道 str.empty()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' 时才有可能出现这种情况。那时你可以说它是一个空字符串。


2

C++中的字符串有空或非空的概念。如果字符串为空,则str [0]未定义。只有当C ++字符串大小> 1时,str [0]才被定义。

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

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