结构中的字符数组 - 为什么 strlen() return 是正确的值?
char array in structs - why does strlen() return the correct value here?
我有一个像这样的简单程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
int numberOfDays;
char name[10];
} Month;
int main(void)
{
const Month months[12] = {
{ 31, {'J', 'a', 'n'} },
{ 28, {'F', 'e', 'b'} }
};
printf("%zu\n", strlen(months[0].name));
printf("%zu\n", sizeof(months[0].name));
printf("%zu\n", strlen(months[1].name));
printf("%zu\n", sizeof(months[1].name));
return 0;
}
输出是这样的:
3
10
3
10
我明白为什么 sizeof(months[i].name)
打印 10,但为什么 strlen
return 在这种情况下是正确的值?
我的想法是,strlen
计数到第一个 '[=16=]'
,但 char name[3]
数组不是空终止的。根据我的理解,这应该是未定义的行为?它只是偶然起作用吗?
我想知道上面的 months[12]
数组中的内存布局是什么。
原因是你的月份确实是nul-terminated。如果你有一个包含 10 个元素的数组,并且有一个 3 个元素的初始化程序,那么其余的将用 0 填充。如果你有一个有 11 个字符的月份,编译器会告诉你。如果一个月有 10 个字符,您就会遇到麻烦,因为没有 null 终止符,编译器也不会告诉您。
TL;DR 回答: 不,这是明确定义的行为。
解释: 根据 C11
标准文档,第 6.7.9 章,初始化,
If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.
在您的例子中,您有一个包含 10
个元素的 char
数组
char name[10];
并且您只为 3 个元素提供了初始值设定项,例如
{ 31, {'J', 'a', 'n'} },
因此,name
中的其余元素被初始化为0
或'[=17=]'
。所以,在这种情况下,strlen()
returns 是正确的结果。
注意:请不要依赖此方法来对字符串进行空终止.如果您提供的元素的确切数量作为初始化器,则不会有 null 终止。
编辑:
如果 name
定义更改为 char name[3]
并用三个 char
初始化,那么,根据上面的注释,使用 strlen()
(和family) 将是 undefined behaviour 因为它会在搜索终止 null 时超出分配的内存区域。
当您部分初始化 struct
时,那些未专门初始化的部分将设置为 0。
所以字符串确实有一个终止 0,所以 strlen()
returns 正确的值。
#include <stdio.h>
#include <string.h>
int main(){
int i;
char s[10] = {'a', 'b', 'c'};
for (i=0; i<10; i++)
printf("%d ", s[i]);
printf("\n%d\n", strlen(s));
return 0;
}
程序输出:
97 98 99 0 0 0 0 0 0 0
3
我有一个像这样的简单程序:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
int numberOfDays;
char name[10];
} Month;
int main(void)
{
const Month months[12] = {
{ 31, {'J', 'a', 'n'} },
{ 28, {'F', 'e', 'b'} }
};
printf("%zu\n", strlen(months[0].name));
printf("%zu\n", sizeof(months[0].name));
printf("%zu\n", strlen(months[1].name));
printf("%zu\n", sizeof(months[1].name));
return 0;
}
输出是这样的:
3
10
3
10
我明白为什么 sizeof(months[i].name)
打印 10,但为什么 strlen
return 在这种情况下是正确的值?
我的想法是,strlen
计数到第一个 '[=16=]'
,但 char name[3]
数组不是空终止的。根据我的理解,这应该是未定义的行为?它只是偶然起作用吗?
我想知道上面的 months[12]
数组中的内存布局是什么。
原因是你的月份确实是nul-terminated。如果你有一个包含 10 个元素的数组,并且有一个 3 个元素的初始化程序,那么其余的将用 0 填充。如果你有一个有 11 个字符的月份,编译器会告诉你。如果一个月有 10 个字符,您就会遇到麻烦,因为没有 null 终止符,编译器也不会告诉您。
TL;DR 回答: 不,这是明确定义的行为。
解释: 根据 C11
标准文档,第 6.7.9 章,初始化,
If there are fewer initializers in a brace-enclosed list than there are elements or members of an aggregate, or fewer characters in a string literal used to initialize an array of known size than there are elements in the array, the remainder of the aggregate shall be initialized implicitly the same as objects that have static storage duration.
在您的例子中,您有一个包含 10
个元素的 char
数组
char name[10];
并且您只为 3 个元素提供了初始值设定项,例如
{ 31, {'J', 'a', 'n'} },
因此,name
中的其余元素被初始化为0
或'[=17=]'
。所以,在这种情况下,strlen()
returns 是正确的结果。
注意:请不要依赖此方法来对字符串进行空终止.如果您提供的元素的确切数量作为初始化器,则不会有 null 终止。
编辑:
如果 name
定义更改为 char name[3]
并用三个 char
初始化,那么,根据上面的注释,使用 strlen()
(和family) 将是 undefined behaviour 因为它会在搜索终止 null 时超出分配的内存区域。
当您部分初始化 struct
时,那些未专门初始化的部分将设置为 0。
所以字符串确实有一个终止 0,所以 strlen()
returns 正确的值。
#include <stdio.h>
#include <string.h>
int main(){
int i;
char s[10] = {'a', 'b', 'c'};
for (i=0; i<10; i++)
printf("%d ", s[i]);
printf("\n%d\n", strlen(s));
return 0;
}
程序输出:
97 98 99 0 0 0 0 0 0 0
3