初始化结构体数组

35

这是我在别人的问题中发现的初始化代码。

my_data data[]={
    { .name = "Peter" },
    { .name = "James" },
    { .name = "John" },
    { .name = "Mike" }
};

我从未见过这样的东西,并且找不到解释为什么 .name 可以正确。


我想了解的是这个过程是如何逐步进行的:

  1. data;
  2. *data;
  3. (*data).name;
  4. (*data).name="Peter";

或者我完全错了吗?


3
这只是C99标准,它已成为过去14年中的C语言标准。 - Paul R
1
你需要逐步操作。你必须熟悉 int a[2] = {0,0} 语法。所以你不知道的只有 {.name = "foo"},这对我来说似乎是不言自明的! - Dave
4
@PaulR,当前的C标准是C11... - Jens Gustedt
@Jens:好观点 - 评论已更新! - Paul R
这对我来说非常有价值,因为我一直在想如何初始化一个结构体数组而不会让自己崩溃。 - Barleyman
1
这是关于编程的内容,请将其翻译成中文。仅返回已翻译的文本:这不是一个重复问题,这个问题要求结构体数组,而不是一个结构体。 - jangorecki
6个回答

47

my_data 是一个结构体,其中包含一个名为 name 的字段,而 data[] 是一个结构体数组,你需要对每个索引进行初始化。请阅读以下内容:

5.20 Designated Initializers:

In a structure initializer, specify the name of a field to initialize with .fieldname =' before the element value. For example, given the following structure,

struct point { int x, y; };

the following initialization

struct point p = { .y = yvalue, .x = xvalue };

is equivalent to

struct point p = { xvalue, yvalue };

Another syntax which has the same meaning, obsolete since GCC 2.5, is fieldname:', as shown here:

struct point p = { y: yvalue, x: xvalue };

您还可以写:

my_data data[] = {
    { .name = "Peter" },
    { .name = "James" },
    { .name = "John" },
    { .name = "Mike" }
};

作为:

my_data data[] = {
    [0] = { .name = "Peter" },
    [1] = { .name = "James" },
    [2] = { .name = "John" },
    [3] = { .name = "Mike" }
}; 

或者:

my_data data[] = {
    [0].name = "Peter",
    [1].name = "James",
    [2].name = "John",
    [3].name = "Mike"
}; 

第二和第三种形式可能更方便,因为您不需要按顺序编写代码。例如,上面的所有示例都等效于:

my_data data[] = {
    [3].name = "Mike",
    [1].name = "James",
    [0].name = "Peter",
    [2].name = "John"
}; 

如果您的结构体中有多个字段(例如,一个int age),您可以使用以下方式一次性初始化所有字段:
my_data data[] = {
    [3].name = "Mike",
    [2].age = 40,
    [1].name = "James",
    [3].age = 23,
    [0].name = "Peter",
    [2].name = "John"
}; 

为了理解数组初始化,请阅读奇怪的初始化表达式? 此外,您还可以阅读@Shafik Yaghmour在switch case方面的答案:C代码中switch-case中的“…”是什么

32

这里只涉及两种语法:

  1. 普通的数组初始化:

    int x[] = {0, 0}; // x[0] = 0, x[1] = 0
    
    指定初始化器。请参见此问题的已接受答案:如何根据C编程语言标准初始化结构体 语法相当自解释。您可以这样初始化:
    struct X {
        int a;
        int b;
    }
    struct X foo = { 0, 1 }; // a = 0, b = 1
    

    或者使用任何排序方式,

    struct X foo = { .b = 0, .a = 1 }; // a = 1, b = 0
    

35
你的例子是关于结构体,而不是结构体数组。 - jangorecki
1
@jangorecki 我将问题分解了一下;第一个例子是关于数组初始化的,第二个例子是关于结构体初始化的。将两者结合起来,你就可以看到 OP 发布的语法如何用于初始化结构体数组,这也是本文的问题所在。 - Dave
6
是的,但“将两者结合起来”实际上是很难实现的...无论如何,在我看到的许多答案中,你的回答对我来说是最有用的。在可以的时候,我会取消点赞。 - jangorecki

26

这里没有“逐步”的过程。当使用常量表达式进行初始化时,该过程实际上是在编译时执行的。当然,如果数组被声明为本地对象,则会在运行时分配并初始化,但仍可视为无法有意义地细分的单步过程。

指定初始化程序允许您为结构体对象的特定成员(或数组的特定元素)提供初始化程序。所有其他成员都将获得零初始化。因此,如果my_data被声明为

typedef struct my_data {
  int a;
  const char *name;
  double x;
} my_data;

那么你的

my_data data[]={
    { .name = "Peter" },
    { .name = "James" },
    { .name = "John" },
    { .name = "Mike" }
};

是“更简洁的形式”的意思。

my_data data[4]={
    { 0, "Peter", 0 },
    { 0, "James", 0 },
    { 0, "John", 0 },
    { 0, "Mike", 0 }
};

我希望你知道后者是做什么的。


3

这被称为C99引入的“指定初始化器”。它用于初始化struct或数组,在这个例子中,是struct

假设有一个

struct point { 
    int x, y;
};

以下是初始化过程:

struct point p = { .y = 2, .x = 1 };

等价于C89风格。
struct point p = { 1, 2 };

2
这很简单: my_data 是一个预定义的结构类型。 因此,您想声明一个包含一些元素的my_data数组,就像您通常所做的一样。
char a[] = { 'a', 'b', 'c', 'd' };

所以这个数组将有4个元素,并且您可以将它们初始化为:
a[0] = 'a', a[1] = 'b', a[1] = 'c', a[1] ='d';

这被称为指定初始化程序(如我所记得的)。
它只是表示数据必须是类型为“my_dat”的数组,并且必须是一个需要存储这么多个my_data结构的数组,以便每个类型成员都有Peter、James、John和Mike这样的一个结构。

1
这是C99标准引入的“指定初始化器”,它允许您按名称初始化结构体或联合对象的特定成员。显然,`my_data` 是一个 `struct` 类型的别名,其中包含一个类型为 `char *` 或 `char [N]` 的成员 `name`。请保留 HTML 标签。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接