在许多代码示例中,人们通常在创建新的 char 数组之后使用 '\0'
,例如:
string s = "JustAString";
char* array = new char[s.size() + 1];
strncpy(array, s.c_str(), s.size());
array[s.size()] = '\0';
我们为什么要在这里使用'\0'
?
在许多代码示例中,人们通常在创建新的 char 数组之后使用 '\0'
,例如:
string s = "JustAString";
char* array = new char[s.size() + 1];
strncpy(array, s.c_str(), s.size());
array[s.size()] = '\0';
我们为什么要在这里使用'\0'
?
你的问题标题提到了C字符串。C++中的std::string
对象和标准C风格的字符串处理方式不同。在使用C字符串时,\0
非常重要,而当我在答案中使用术语“字符串”时,我是指“标准C字符串”。
\0
作为字符串终止符在C语言中起作用。它被称为“空字符”或“NUL”,标准C字符串是以它为结尾的。这个终止符通知处理字符串的代码 - 标准库以及你自己的代码 - 字符串的结束位置在哪里。一个很好的例子是strlen
,它返回字符串的长度:strlen
的工作原理是基于字符串以\0
结尾的假设。
当你声明一个常量字符串时:
const char *str = "JustAString";
如果你处理的是常量字符串,那么\0
会自动添加。但如果像你的数组示例一样处理非常量字符串,有时需要自己处理它。在你的示例中使用的 strncpy 的文档是一个很好的例子:strncpy
复制了空终止字符除外,当指定长度达到之前就复制了整个字符串。因此,通常会看到将 strncpy
与可能多余的空终止符赋值结合在一起。为了解决由于忽略处理此情况而引起的潜在问题,设计了 strlcpy
和 strcpy_s
。
在你的特定示例中,array[s.size()] = '\0';
是一种冗余:由于array
的大小是 s.size() + 1
,而 strncpy
正在复制 s.size()
个字符,函数将附加 \0
。
标准 C 字符串实用程序的文档将指示何时需要小心包括这样的空终止符。但要仔细阅读文档:与 strncpy
一样,细节很容易被忽略,导致潜在的缓冲区溢出。
c_str()
,那么您将获得一个正确终止的缓冲区,但这只是因为您礼貌地请求了。 - tadmanstd::string
可能会分配比请求的数量稍微多一点,这是实现定义的,因此可能已经存在零填充。 - tadmanc_str()
时动态分配一个单独的缓冲区,其中包含NUL终止符,并返回该缓冲区...但是对于长字符串来说,这当然会非常低效,并可能导致内存泄漏。因此,我的假设是每个生产就绪的std::string
实现实际上都只是在内部存储了一个以NUL结尾的字符串,以便c_str()
可以简单地返回指向它的指针。 - Jeremy Friesnerc_str()
时进行分配并不是非常理想,因此可能不会这样做。如果您处于无法假设的位置,请进行测试,并探索在长度从1到1GB变化时它的行为如何,因为某些大小可能是“有问题的”。 - tadman为什么C++中的字符串通常以
'\0'
结尾?
需要注意的是,C++字符串和C字符串不同。
在C++中,字符串指的是模板类std::string,提供了许多直观的函数来处理字符串。
需要注意的是,C++的std::string不是以\0
结尾的,但该类提供了函数以获取底层的\0
结尾的C风格字符串。
在C语言中,字符串是一组字符。这个集合通常以\0
结束。
除非使用像\0
这样的特殊字符,否则就无法知道字符串何时结束。
它也准确地称为字符串结束符。
当然,可能有其他方式来跟踪字符串的长度,但使用特殊字符具有两个明显的优点:
需要注意的是,\0
是必需的,因为大多数标准C库函数都假定它们操作的字符串是以\0
结尾的。
例如:
如果你有一个不以\0
结尾的字符串,而你使用printf()
函数,则printf()
会持续向stdout
写入字符,直到遇到\0
为止。
为什么我们要在这里使用
'\0'
?
有两种情况不需要使用\0
终止字符串:
\0
添加到字符串中。在您的情况下,第二种情况已经适用于您。
array[s.size()] = '\0';
在您的示例中,上述代码语句是多余的。
对于您的示例,使用strncpy()
使其变得无用。 strncpy()
将s.size()
个字符复制到您的array
中,并在复制字符串后追加空终止符(null termination)。由于array
的大小为s.size() + 1
,因此\0
会自动添加。
'\0'是空字符终止符。如果您的字符数组没有它,而您尝试进行strcpy,则会发生缓冲区溢出。许多函数依赖于它来知道何时需要停止读取或写入内存。
strncpy(array, s.c_str(), s.size());
array[s.size()] = '\0';
strncpy(array, s.c_str(), s.size()+1);
strncpy 是一个有点奇怪的函数,它假设第一个参数是大小为第三个参数的数组。所以只有在复制字符串后还有剩余空间时才会复制空结束符。
在这种情况下,你也可以使用 memcpy() ,尽管这可能会使代码更难以理解,但它会略微提高效率。
strcpy(array, &s[0]);
。这个长度是 std::strlen(&s[0])+1 个字符。如果你想复制到第一个 \0 并用 \0 填充剩余部分,可以使用 strncpy(array, &s[0], s.size()+1);
。如果你想从 &s[0] 复制给定大小,可以使用 memcpy(array, &s[0], s.size()+1);
。(因此嵌入的 \0 不会清除字符串的其余部分) - Puddle
string.h
中的函数将无法按预期工作。 - nhahtdh