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

Max*_*Max 17 c initialization

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

#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;
}
Run Code Online (Sandbox Code Playgroud)

输出是这样的:

3
10
3
10
Run Code Online (Sandbox Code Playgroud)

我理解为什么sizeof(months[i].name)打印10,但为什么strlen在这种情况下返回正确的值?

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

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

Sou*_*osh 26

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

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

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

在您的情况下,您有char一系列10元素

 char name[10];
Run Code Online (Sandbox Code Playgroud)

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

{ 31, {'J', 'a', 'n'} },
Run Code Online (Sandbox Code Playgroud)

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

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


编辑:

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


gna*_*729 8

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