检查数组中未初始化的结构

Check for uninitialized structs in an array

据我所知,如果你在 C 中得到一个数组并使用一个大小和小于该大小的项目数对其进行初始化,则该数组将使用给定的项目和数组中的其余位置进行初始化初始化为 0 或最有代表性的 0 值。 但是,当你有一个 struct something 类型的数组时,我如何检查数组中的特定索引是已初始化的还是未初始化的?

喜欢:

struct a {
    char x[20];
    int y;
};
typedef struct a a;

a a[5] = {
    {.x = "name", .y = 1},
    {.x = "surname", .y = 2}
};

在这种情况下,数组中的前两个索引是给定的初始化结构,但其他索引是什么?如果我访问的索引是已初始化或未初始化的,我应该如何检查以后的实现?

当数组中的至少一个条目被赋予初始值设定项时,任何剩余的未初始化条目都被初始化为零。所以你可以通过在结构中添加一个bool来解决问题:

struct a {
    bool valid;
    char x[20];
    int y;
};
typedef struct a a;

a a[5] = {
    {.valid = true, .x = "name", .y = 1},
    {.valid = true, .x = "surname", .y = 2}
};

valid 前两项为 true,其余为 false

您的问题的解决方案

请注意,这在一定程度上取决于您对 initialized 的实际含义。在您的示例中,就 C 标准而言,整个数组确实已初始化。按照这个初始化的定义,是没办法的。读取未初始化对象的值是未定义的行为,C 中没有 isinitialized 运算符。但是你的情况,你可以放心,整个数组都是按照标准初始化的。详情见下文。

但这不是初始化的唯一合理定义。如果我们以 a[2]a[3]a[4] 在您的情况下被视为未初始化的方式放宽一点,则有一些方法。它们各有利弊,请注意,要使用这些方法中的任何一种,都需要根据 C 标准对数组进行初始化。

单独的布尔字段

您可以像 user3386109 在他们的 中那样做,并添加一个单独的布尔字段。

缺点:需要一个额外的字段

哨兵值

另一种方法是使用标记值。例如,您可以决定如果 .x 是一个空字符串,或者包含字符串“null”或“未初始化”,或者如果 .y 是一个负数,或者其他什么,那么数组元素应该被认为是未初始化的。这并不总是一个可行的选择。

缺点:从可能值集中删除一个值

指针

您可以拥有指向结构的指针数组,并将 NULL 指针视为未初始化的结构,而不是结构数组。像这样:

struct a *arr[5] = { NULL };
arr[3] = malloc(sizeof(*arr[0]));
strcpy((*arr[3]).x, "Hello, World!");
(*arr[3]).y = 5;
for(int i=0; i<5; i++) {
    if(arr[i])
        printf("%d is initialized with y: %d x: %s\n", 
               i, (*arr[i]).y, (*arr[i]).x);
    else
        printf("%d is not initialized\n", i);
}

缺点:指针

关于数组初始化的详细信息

标准是这样说的:

https://port70.net/~nsz/c/c11/n1570.html#6.7.9p21

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.

我们还可以读到这个:

https://port70.net/~nsz/c/c11/n1570.html#6.2.5p21

Arithmetic types and pointer types are collectively called scalar types. Array and structure types are collectively called aggregate types.

所以数组是集合,因此适用静态存储持续时间的规则。让我们看看标准对此有何评论。

https://port70.net/~nsz/c/c11/n1570.html#6.7.9p10

If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static or thread storage duration is not initialized explicitly, then:

  • 如果是指针类型,则初始化为空指针;
  • 如果是算术类型,则初始化为(正数或无符号)零;
  • 如果是聚合,则每个成员都根据这些规则(递归)初始化,任何填充都初始化为零位;
  • 如果是联合,则根据这些规则(递归)初始化第一个命名成员,并将任何填充初始化为零位;

因此,如果您已经初始化了数组中的一个元素,则其余元素将归零。即使对于包含枚举和联合的结构数组也是如此。但是绝对没有办法对此进行运行时检查。