结构中的char数组 – 为什么strlen()在这里返回正确的值?

我有一个这样的简单程序:

#include  #include  #include  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在这种情况下返回正确的值?

我的想法是, strlen计数直到第一个'\0' ,但char name[3]数组不是null终止。 从我的理解,这应该是未定义的行为? 它只是偶然工作吗?

我想知道上面months[12]数组中的内存布局是什么。

TL; DR答案:不,这是明确定义的行为。

说明:根据C11标准文件,第6.7.9章,初始化,

如果括号括起的列表中的初始值设定项少于聚合的元素或成员,或者用于初始化已知大小的数组的字符串文字中的字符数少于数组中的元素,则聚合的其余部分应为隐式初始化与具有静态存储持续时间的对象相同。

在您的情况下,您有一个包含10元素的char数组

  char name[10]; 

并且你只为3个元素提供了初始化程序,比如

 { 31, {'J', 'a', 'n'} }, 

因此,名称中的其余元素初始化为0'\0' 。 因此,在这种情况下, strlen()返回正确的结果。

注意:请不要依赖此方法来终止字符串 。 如果您提供的元素的确切数量为initalizer,则不会出现空终止。


编辑:

如果name定义更改为char name[3]并使用三个char初始化,那么,根据上面的注释, strlen() (和family)的使用将是未定义的行为 ,因为它将超出分配的内存区域。搜索终止null。

原因是你的月份确实已经终止了。 如果你有一个包含10个元素的数组,并且有3个元素的初始化器,那么剩下的就用0填充。 如果您有一个包含11个字符的月份,编译器会告诉您。 如果你有一个10个字符的月份,你会遇到麻烦,因为没有nul-termination,编译器也不会告诉你。

部分初始化struct ,未特别初始化的那些部分将设置为0。

所以字符串确实有一个终止0,因此strlen()返回正确的值。

 #include  #include  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