考虑以下代码:
char str[] = "Hello\0";
str数组的长度是多少,并以多少个0结尾?
考虑以下代码:
char str[] = "Hello\0";
str数组的长度是多少,并以多少个0结尾?
sizeof str
是 7,"Hello" 文本占了五个字节,加上显式的 NUL 结束符和隐含的 NUL 结束符。
strlen(str)
是 5,只计算了 "Hello" 的五个字节。
关键在于隐含的 NUL 结束符总是被添加——即使字符串字面值恰好以 \0
结尾也是如此。当然,strlen
在第一个 \0
处停止——它无法区分两者。
有一个例外是,如果你明确指定了数组大小,字符串将会被截断以适应指定大小:
char str[6] = "Hello\0"; // strlen(str) = 5, sizeof(str) = 6 (with one NUL)
char str[7] = "Hello\0"; // strlen(str) = 5, sizeof(str) = 7 (with two NULs)
char str[8] = "Hello\0"; // strlen(str) = 5, sizeof(str) = 8 (with three NULs per C99 6.7.8.21)
然而,这很少有用,并且容易计算字符串长度错误,导致未终止的字符串。在C++中也被禁止使用。
char [8]
示例看起来有误。如果原作者使用 char str[8] = { 'H', 'e', 'l', 'l', 'o', '\0', '\0' }
,那么剩余字符的值将 不会 是未定义的,而是零(这样你就可以合理地初始化例如 int arr[100] = { 0 }
以使其全部为零)。我不明白为什么对于字符串 "Hello\0"
而言,它与长形式是不同的,除非标准在这种情况下有明确的例外规定(这对我来说似乎非常奇怪)。 - Chris Lutz这个数组的长度为7,NUL字符\0
仍然计算在字符中,并且字符串以隐式的\0
结尾。
请查看此链接以查看一个工作示例。
请注意,如果您将str
声明为char str[6] = "Hello\0";
,则长度将为6,因为只有在可以适合时才会添加隐式NUL(在这个例子中不能)。
§ 6.7.8/p14
字符类型的数组可以通过用括号括起来的字符字符串字面值进行初始化。 字符串字面值的连续字符(包括终止零字符如果有空间或如果数组大小未知)初始化数组的元素。
char str[] = "Hello\0"; /* sizeof == 7, Explicit + Implicit NUL */
char str[5]= "Hello\0"; /* sizeof == 5, str is "Hello" with no NUL (no longer a C-string, just an array of char). This may trigger compiler warning */
char str[6]= "Hello\0"; /* sizeof == 6, Explicit NUL only */
char str[7]= "Hello\0"; /* sizeof == 7, Explicit + Implicit NUL */
char str[8]= "Hello\0"; /* sizeof == 8, Explicit + two Implicit NUL */
sizeof
运算符返回7。 - Chris LutzC
语言中,“长度”和“大小”这两个词在字符串方面有不同的含义。在我的回答中,我指的是后者。 - SiegeX
$ cat junk.c
#include <stdio.h>
char* string = "Hello\0";
int main(int argv, char** argc)
{
printf("-->%s<--\n", string);
}
$ gcc -S junk.c
$ cat junk.s
.LC0:
.string "Hello"
.string ""
...
.LC1:
.string "-->%s<--\n"
注意我在使用printf时的字符串只是"-->%s<---\n"
,而全局字符串由两部分组成:"Hello"
和""
。GNU汇编器也会用隐含的NUL
字符来终止字符串,因此第一个字符串(.LC0)被分为两个部分意味着有两个NUL
。因此该字符串长度为7个字节。如果你真的想知道编译器对某个代码块的处理方式,可以将其隔离到像这样的虚拟示例中,并使用-S
查看它的操作方式(GNU为此提供了一个选项,MSVC也有一个汇编输出标志,但我不记得了)。你将学习到有关如何使代码工作(或者无法正常工作)的很多知识,并且你将很快得到一个100%与你所使用的工具和环境相匹配的答案。
int main() {
char str[] = "Hello\0";
int length = sizeof str / sizeof str[0];
// "sizeof array" is the bytes for the whole array (must use a real array, not
// a pointer), divide by "sizeof array[0]" (sometimes sizeof *array is used)
// to get the number of items in the array
printf("array length: %d\n", length);
printf("last 3 bytes: %02x %02x %02x\n",
str[length - 3], str[length - 2], str[length - 1]);
return 0;
}
'\0' 被称为 NULL 字符或 NULL 终止符 它是整数 0(零)的字符等效物,因为它指代了空值
在 C 语言中,它通常用于标记字符串的结尾。 例如字符串 a="Arsenic"; 每个字符都存储在一个数组中。
a[0]=A
a[1]=r
a[2]=s
a[3]=e
a[4]=n
a[5]=i
a[6]=c
数组的末尾包含''\0',以停止字符串'a'的数组内存分配。
char str[]= "Hello\0";
这将是7个字节。
在内存中,它将是:
48 65 6C 6C 6F 00 00
H e l l o \0 \0
编辑:
C字符串中的\0符号代表什么意思?
它是字符串的“结尾”。一个空字符。在内存中,实际上是零。通常处理字符数组的函数会寻找这个字符,因为这是消息的末尾。我会在最后放一个例子。
str数组的长度是多少?(在编辑部分之前已回答)
7
以及以多少个0结尾?
你的数组有两个带零的“空位”;str[5]=str[6]='\0'=0
额外的例子:
假设你有一个打印文本数组内容的函数。
你可以将其定义为:
char str[40];
现在,您可以更改该数组的内容(我不会详细介绍如何操作),以便其中包含消息:“这只是一个打印测试” 在内存中,您应该有类似以下的东西:
54 68 69 73 20 69 73 20 6a 75 73 74 20 61 20 70 72 69 6e 74
69 6e 67 20 74 65 73 74 00 00 00 00 00 00 00 00 00 00 00 00
所以你打印那个字符数组。然后你想要一个新的消息。比如说“你好”
48 65 6c 6c 6f 00 73 20 6a 75 73 74 20 61 20 70 72 69 6e 74
69 6e 67 20 74 65 73 74 00 00 00 00 00 00 00 00 00 00 00 00
str
是一个大小为7的数组,包括七年前被接受的答案。为什么要再次重复它(而不添加任何新内容)? - melpomene