Why/when 以包含 C 字符串的终止字符“\0”?
Why/when to include terminating '\0' character for C Strings?
我是 C 的新手,对于何时需要手动将终止字符“\0”添加到字符串,我感到有些困惑。给定这个函数来计算字符串长度(为了清楚起见):
int stringLength(char string[])
{
int i = 0;
while (string[i] != '[=11=]') {
i++;
}
return i;
}
根据空终止字符计算字符串的长度。那么,使用以下情况,'\0'字符的作用是什么?
案例 1:
char * stack1 = "stack";
printf("WORD %s\n", stack1);
printf("Length %d\n", stringLength(stack1));
打印:
WORD stack
Length 5
案例 2:
char stack2[5] = "stack";
printf("WORD %s\n", stack2);
printf("Length %d\n", stringLength(stack2));
打印:
WORD stack���
Length 8
(这些结果每次都不同,但永远不会正确)。
案例 3:
char stack3[6] = "stack";
printf("WORD %s\n", stack3);
printf("Length %d\n", stringLength(stack3));
打印:
WORD stack
Length 5
案例 4:
char stack4[6] = "stack";
stack4[5] = '[=18=]';
printf("WORD %s\n", stack4);
printf("Length %d\n", stringLength(stack4));
打印:
WORD stack
Length 5
案例 5:
char * stack5 = malloc(sizeof(char) * 5);
if (stack5 != NULL) {
stack5[0] = 's';
stack5[1] = 't';
stack5[2] = 'a';
stack5[3] = 'c';
stack5[4] = 'k';
printf("WORD %s\n", stack5);
printf("Length %d\n", stringLength(stack5));
}
free(stack5);
打印:
WORD stack
Length 5
案例 6:
char * stack6 = malloc(sizeof(char) * 6);
if (stack6 != NULL) {
stack6[0] = 's';
stack6[1] = 't';
stack6[2] = 'a';
stack6[3] = 'c';
stack6[4] = 'k';
stack6[5] = '[=22=]';
printf("WORD %s\n", stack6);
printf("Length %d\n", stringLength(stack6));
}
free(stack6);
打印:
WORD stack
Length 5
也就是说,我想知道情况 1、2、3 和 4 之间的区别(以及为什么情况 2 的行为不稳定,并且不需要在 1 和 3 中指定空终止字符。此外, 3 和 4 如何工作相同?)以及 5 和 6 如何打印出相同的东西,即使在情况 5 中没有为空终止字符分配足够的内存(因为只为 [= 中的每个字母分配了 5 个字符槽) 58=],它如何检测'\0'字符,即第6个字符?)
对于这个长得荒谬的问题,我感到非常抱歉,只是我在其他任何地方都找不到对这些特定实例的良好教学解释
字符串的存储必须始终为终止空字符留出空间。在您的某些示例中,您没有这样做,而是明确给出了 5 的长度。在这些情况下,您将得到未定义的行为。
String literals 始终自动获取空终止符。尽管strlen
returns 长度为5,但实际上占用了6 个字节。
您的案例 5 之所以有效,是因为 undefined 有时意味着它看起来有效。您可能在内存中的字符串后面有一个零值 - 但您不能依赖它。
在情况 1 中,您正在创建一个字符串文字(将在只读内存中的常量),其中将隐式添加 [=13=]
。
由于 [=13=]
的位置依赖于找到字符串的结尾,因此您的 stringLength()
函数打印 5
.
在情况 2 中,您尝试使用 5 个字符的字符串初始化大小为 5 的字符数组,不为 [=13=]
分隔符留下 space。与字符串相邻的内存可以是任何东西,并且可能在某处有一个 [=13=]
。这个 [=13=]
被认为是字符串的结尾,它解释了你得到的那些奇怪的字符。似乎对于您提供的输出,此 [=13=]
仅在另外 3 个字符之后才被发现,这些字符在计算字符串长度时也被考虑在内。由于内存的内容随时间变化,输出可能并不总是相同的。
在情况 3 中,您正在使用大小为 5 的字符串初始化大小为 6 的字符数组,留下足够的 space 来存储将被隐式存储的 [=13=]
。因此,它将正常工作。
案例4与案例3类似,没有做任何修改
char stack4[5] = '[=10=]';
因为 stack4
的大小是 6,因此它的最后一个索引是 5。你正在用它的旧值本身覆盖一个变量。 stack4[5]
甚至在您覆盖它之前就已经包含了 [=13=]
。
在情况 5 中,您已经用字符完全填充了字符数组,没有为 [=13=]
留下 space。然而,当您打印字符串时,它打印正确。我认为这是因为与 malloc()
分配的内存相邻的内存恰好为零,即 [=13=]
的值。但这是未定义的行为,不应依赖。真正发生的事情取决于实施。
需要注意的是 malloc()
不会初始化它分配的内存,不像 calloc()
.
两者都
char str[2]='[=11=]';
和
char str[2]=0;
都一样。
但你不能指望它为零。由于操作系统的工作和安全原因,动态分配的内存可能具有零作为默认值。有关详细信息,请参阅 here and here。
如果需要动态分配内存的默认值为零,可以使用calloc()
.
案例6最后是[=13=]
,其他位置是字符。打印时应显示正确的字符串。
我是 C 的新手,对于何时需要手动将终止字符“\0”添加到字符串,我感到有些困惑。给定这个函数来计算字符串长度(为了清楚起见):
int stringLength(char string[])
{
int i = 0;
while (string[i] != '[=11=]') {
i++;
}
return i;
}
根据空终止字符计算字符串的长度。那么,使用以下情况,'\0'字符的作用是什么?
案例 1:
char * stack1 = "stack";
printf("WORD %s\n", stack1);
printf("Length %d\n", stringLength(stack1));
打印:
WORD stack
Length 5
案例 2:
char stack2[5] = "stack";
printf("WORD %s\n", stack2);
printf("Length %d\n", stringLength(stack2));
打印:
WORD stack���
Length 8
(这些结果每次都不同,但永远不会正确)。
案例 3:
char stack3[6] = "stack";
printf("WORD %s\n", stack3);
printf("Length %d\n", stringLength(stack3));
打印:
WORD stack
Length 5
案例 4:
char stack4[6] = "stack";
stack4[5] = '[=18=]';
printf("WORD %s\n", stack4);
printf("Length %d\n", stringLength(stack4));
打印:
WORD stack
Length 5
案例 5:
char * stack5 = malloc(sizeof(char) * 5);
if (stack5 != NULL) {
stack5[0] = 's';
stack5[1] = 't';
stack5[2] = 'a';
stack5[3] = 'c';
stack5[4] = 'k';
printf("WORD %s\n", stack5);
printf("Length %d\n", stringLength(stack5));
}
free(stack5);
打印:
WORD stack
Length 5
案例 6:
char * stack6 = malloc(sizeof(char) * 6);
if (stack6 != NULL) {
stack6[0] = 's';
stack6[1] = 't';
stack6[2] = 'a';
stack6[3] = 'c';
stack6[4] = 'k';
stack6[5] = '[=22=]';
printf("WORD %s\n", stack6);
printf("Length %d\n", stringLength(stack6));
}
free(stack6);
打印:
WORD stack
Length 5
也就是说,我想知道情况 1、2、3 和 4 之间的区别(以及为什么情况 2 的行为不稳定,并且不需要在 1 和 3 中指定空终止字符。此外, 3 和 4 如何工作相同?)以及 5 和 6 如何打印出相同的东西,即使在情况 5 中没有为空终止字符分配足够的内存(因为只为 [= 中的每个字母分配了 5 个字符槽) 58=],它如何检测'\0'字符,即第6个字符?)
对于这个长得荒谬的问题,我感到非常抱歉,只是我在其他任何地方都找不到对这些特定实例的良好教学解释
字符串的存储必须始终为终止空字符留出空间。在您的某些示例中,您没有这样做,而是明确给出了 5 的长度。在这些情况下,您将得到未定义的行为。
String literals 始终自动获取空终止符。尽管strlen
returns 长度为5,但实际上占用了6 个字节。
您的案例 5 之所以有效,是因为 undefined 有时意味着它看起来有效。您可能在内存中的字符串后面有一个零值 - 但您不能依赖它。
在情况 1 中,您正在创建一个字符串文字(将在只读内存中的常量),其中将隐式添加 [=13=]
。
由于 [=13=]
的位置依赖于找到字符串的结尾,因此您的 stringLength()
函数打印 5
.
在情况 2 中,您尝试使用 5 个字符的字符串初始化大小为 5 的字符数组,不为 [=13=]
分隔符留下 space。与字符串相邻的内存可以是任何东西,并且可能在某处有一个 [=13=]
。这个 [=13=]
被认为是字符串的结尾,它解释了你得到的那些奇怪的字符。似乎对于您提供的输出,此 [=13=]
仅在另外 3 个字符之后才被发现,这些字符在计算字符串长度时也被考虑在内。由于内存的内容随时间变化,输出可能并不总是相同的。
在情况 3 中,您正在使用大小为 5 的字符串初始化大小为 6 的字符数组,留下足够的 space 来存储将被隐式存储的 [=13=]
。因此,它将正常工作。
案例4与案例3类似,没有做任何修改
char stack4[5] = '[=10=]';
因为 stack4
的大小是 6,因此它的最后一个索引是 5。你正在用它的旧值本身覆盖一个变量。 stack4[5]
甚至在您覆盖它之前就已经包含了 [=13=]
。
在情况 5 中,您已经用字符完全填充了字符数组,没有为 [=13=]
留下 space。然而,当您打印字符串时,它打印正确。我认为这是因为与 malloc()
分配的内存相邻的内存恰好为零,即 [=13=]
的值。但这是未定义的行为,不应依赖。真正发生的事情取决于实施。
需要注意的是 malloc()
不会初始化它分配的内存,不像 calloc()
.
两者都
char str[2]='[=11=]';
和
char str[2]=0;
都一样。
但你不能指望它为零。由于操作系统的工作和安全原因,动态分配的内存可能具有零作为默认值。有关详细信息,请参阅 here and here。
如果需要动态分配内存的默认值为零,可以使用calloc()
.
案例6最后是[=13=]
,其他位置是字符。打印时应显示正确的字符串。