为什么我们需要在 C++ 字符串中使用空终止符?

Why do we need a null terminator in C++ strings?

我是编程的新手,也是 C++ 的新手,我最近遇到了字符串。

为什么我们需要在字符列表的末尾有一个空终止符?

我读过这样的答案,因为我们可能不会使用数组的所有空间,因此我们需要程序的空终止符来知道字符串在哪里结束,例如char[100] = "John" 但是为什么程序不能循环遍历数组来检查填充了多少空格并因此决定长度?

而如果"John"这个词的数组只填了四个字符,那么其他的空格是怎么填的呢?

数组char john[100] = "John"中的其他字符将用零填充,都是null-terminators .一般来说,当你初始化一个数组,没有提供足够的元素来填满它时,剩下的元素是default-initialized:

int foo[3] {5};           // this is {5, 0, 0}
int bar[3] {};            // this is {0, 0, 0}

char john[5] = "John";    // this is {'J', 'o', 'h', 'n', 0}
char peter[5] = "Peter";  // ERROR, initializer string too long
                          // (one null-terminator is mandatory)

另见 cppreference on Array initialization。要找到这样一个字符串的长度,我们只需循环遍历字符,直到找到 0 并退出。

C++ 中 null-terminating 字符串背后的动机是确保与使用 null-terminated 字符串的 C-libraries 兼容。另见 What's the rationale for null terminated strings?

std::string这样的容器不需要字符串是null-terminated,甚至可以存储包含null-characters的字符串。这是因为它们分别存储字符串的大小。但是,std::string 的字符通常是 null-terminated,因此 std::string::c_str() 不需要修改基础数组。

只有 C++ 的库很少 - 如果曾经 - 在函数之间传递 C-strings。

空终止符的存在是一项设计决定。它的作用是标记字符串的结尾。还有其他方法可以做到这一点,例如在 Pascal 中,字符串的第一个元素是它的大小,因此不需要空终止符。

在你给出的例子中,只有数组的前5个元素会被初始化,其余的都是零初始化。注意我说的是 5 个元素而不是四个。第五个元素是空终止符。

当然程序可以循环遍历字符串以找出它的长度,但它如何知道何时停止循环?

nul 终止符告诉您填充了哪些空格。包括 nul 终止符在内的所有内容都已填充。之后的一切都没有。

对于 数组 的哪些元素已被填充没有一般概念。数组包含一定数量的元素;它的大小是在创建时确定的。它的所有元素最初都有一些价值;通常,无法通过查看元素的值来确定哪些已分配值,哪些未分配值。

字符串是 char 的数组,一种编码约定,即字符串的“结尾”由 nul 字符标记。大多数字符串操作函数都依赖于此约定。

一个字符串文字,例如"John",是一个char的数组。 "John" 数组中有 5 个元素:'J''o''h''n''[=19=]'。例如,函数 strcpy 复制字符,直到它看到 nul 终止符:

char result[100]; // no meaningful values here
strcpy(result, "John");

调用strcpy后,result的前五个元素分别为'J''o''h''n'、和 '[=19=]'。其余数组元素没有有意义的值。

如果我不提及这种字符串风格来自 C,并且通常被称为 C-style 字符串,那将是我的失职。 C++ 支持所有 C 字符串的东西,但它也有一个更复杂的字符串概念,std::string,这是完全不同的。通常,您应该使用 C++ 风格的字符串而不是 C-style 字符串。