【问题标题】:char array in structs - why does strlen() return the correct value here?结构中的字符数组 - 为什么 strlen() 在这里返回正确的值?
【发布时间】:2015-04-14 11:39:04
【问题描述】:

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

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

我的想法是,strlen 一直计数到第一个 '\0',但 char name[3] 数组不是以空值结尾的。据我了解,这应该是未定义的行为?它只是偶然起作用吗?

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

【问题讨论】:

  • 错误。这不是UB。结构的其余部分被初始化为零。
  • 对不起,我的坏人。在结构中写了char name[10],但在问题中我谈到了char name[3]。两者都有效,这让我很惊讶。
  • @Max 请不要以使已经提供的答案看起来脱离上下文的方式编辑问题。谢谢。
  • 在您编辑之前更有意义 - sizeof 结果。

标签: c initialization


【解决方案1】:

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

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

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

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

 char name[10];

你只为 3 个元素提供了初始化器,比如

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

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

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


编辑:

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

【讨论】:

  • 在这种情况下,你幸运的,因为只有“碰巧”是一个终止的 0。
  • @WeatherVane 不走运;只是小整数的一些字节恰好是 0,而且(我认为)Sourav 的大括号初始化规则会用 0 填充数组中剩余的 10 个月。所以 strlen() 会起作用,但会返回意外的长度。
  • @PeterSchneider 这就是我所说的“幸运”。终止的 0 不是数组 [3] 的一部分:它不是设计的,而是偶然的。
  • @PeterSchneider OP 更改了代码,如果您担心的话。
  • @Max 它并没有你想象的那么大。与Pareto Principle 有点关系。 ;-)
【解决方案2】:

原因是您的月份确实是 nul 终止的。如果您有一个包含 10 个元素的数组,并且有一个用于 3 个元素的初始化程序,那么其余部分将填充 0。如果你有一个月有 11 个字符,编译器会告诉你。如果你有一个月有 10 个字符,你会遇到麻烦,因为没有 nul 终止,编译器不会告诉你。

【讨论】:

    【解决方案3】:

    当您部分初始化struct 时,那些未专门初始化的部分将设置为 0。

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

    #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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-12-04
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-12-24
      • 1970-01-01
      • 2018-10-19
      相关资源
      最近更新 更多