简体   繁体   English

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

[英]Check for uninitialized structs in an array

As far as I know if you got an array in C and initialize it with a size and a number of items less then the size, the array is initialized with the given items and the rest of the places in the array are initialized with 0 or a value that's most representative to 0. But what is it like, when you've got an array of type struct something and how can I check if that specific index in the array is an initialized or uninitialized one?据我所知,如果您在 C 中有一个数组并使用大小和小于该大小的项目数对其进行初始化,则使用给定项目初始化数组,并且数组中位置的 rest 初始化为 0 或一个最能代表 0 的值。但是,当你有一个 struct 类型的数组时,我如何检查数组中的特定索引是已初始化的还是未初始化的?

Like:喜欢:

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

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

In this case the first two indexes in the array are the given initialized structs but what are the others one and how should I check in a later implementation if the index I am accessing is an initialized or uninitialized one?在这种情况下,数组中的前两个索引是给定的初始化结构,但其他索引是什么?如果我正在访问的索引是已初始化或未初始化的,我应该如何检查以后的实现?

Solutions to your problem解决您的问题

Note that it depends a bit on what you actually mean with initialized .请注意,这在一定程度上取决于您对initialized的实际含义。 In your example, the whole array is indeed initialized as far as the C standard is concerned.在您的示例中,就 C 标准而言,整个数组确实已初始化。 According to this definition of initialization, there is no way to do it.按照这个初始化的定义,是没有办法的。 Reading the value of an uninitialized object is undefined behavior, and there is no isinitialized operator in C.读取未初始化的 object 的值是未定义的行为,并且 C 中没有isinitialized运算符。 But in your case, you can rest assured that the whole array is initialized according to the standard.但是在你的情况下,你可以保证整个数组按照标准进行初始化。 See below for details.详情见下文。

But that's not the only sensible definition of initialization.但这不是初始化的唯一合理定义。 If we relax it a bit in such a way that a[2] , a[3] and a[4] are to be considered uninitialized in your case there are methods.如果我们稍微放松一下,在您的情况下将a[2]a[3]a[4]视为未初始化,则有一些方法。 All of them have their pros and cons, and please note that in order to use any of these methods, the array needs to be initialized according to the C standard.它们各有利弊,请注意,要使用这些方法中的任何一种,都需要根据 C 标准对数组进行初始化。

Separate Boolean field单独的 Boolean 字段

You could do as user3386109 did in their answer and add a separate Boolean field.您可以像 user3386109 在他们的回答中所做的那样,添加一个单独的 Boolean 字段。

Drawback: Requires an extra field缺点:需要一个额外的字段

Sentinel values哨兵价值观

Another method is to use sentinel values.另一种方法是使用标记值。 For instance, you could decide that if .x is an empty string, or contains the string "null" or "uninitialized", or if .y is a negative number, or whatever, then the array element should be considered uninitialized.例如,您可以决定如果.x是一个空字符串,或者包含字符串“null”或“uninitialized”,或者如果.y是一个负数,或者其他什么,那么应该将数组元素视为未初始化。 This is not always a viable option.这并不总是一个可行的选择。

Drawback: Removes a value from the set of possible values缺点:从可能值集中删除一个值

Pointers指针

Instead of an array of structs, you can have an array of pointers to structs and treat a NULL pointer as an uninitialized struct.您可以使用指向结构的指针数组来代替结构数组,并将 NULL 指针视为未初始化的结构。 Like this:像这样:

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);
}

Drawback: Pointers缺点:指针

Details about initializations of arrays arrays的初始化细节

This is what the standard says:这就是标准所说的:

https://port70.net/~nsz/c/c11/n1570.html#6.7.9p21 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.如果大括号括起来的列表中的初始值设定项少于聚合的元素或成员,或者用于初始化已知大小数组的字符串文字中的字符少于数组中的元素,则聚合的其余部分应隐式初始化与具有 static 存储持续时间的对象相同。

We can also read this:我们也可以阅读这个:

https://port70.net/~nsz/c/c11/n1570.html#6.2.5p21 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.数组和结构类型统称为聚合类型。

So arrays are aggregates, and thus the rules for static storage duration applies.所以 arrays 是聚合,因此适用 static 存储持续时间的规则。 Let's see what the standard has to say about that.让我们看看标准对此有何评论。

https://port70.net/~nsz/c/c11/n1570.html#6.7.9p10 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.如果具有自动存储持续时间的 object 未显式初始化,则其值不确定。 If an object that has static or thread storage duration is not initialized explicitly, then:如果具有 static 或线程存储持续时间的 object 未显式初始化,则:

  • if it has pointer type, it is initialized to a null pointer;如果是指针类型,则初始化为 null 指针;
  • if it has arithmetic type, it is initialized to (positive or unsigned) zero;如果它具有算术类型,则将其初始化为(正或无符号)零;
  • if it is an aggregate, every member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;如果是聚合,则根据这些规则(递归地)初始化每个成员,并且将任何填充初始化为零位;
  • if it is a union, the first named member is initialized (recursively) according to these rules, and any padding is initialized to zero bits;如果是联合,则根据这些规则(递归)初始化第一个命名成员,并将任何填充初始化为零位;

So if you have initialized one element in an array, the rest is zeroed.因此,如果您已初始化数组中的一个元素,则 rest 将归零。 Even for arrays of structs containing an enum and a union.即使对于包含枚举和联合的结构的 arrays 也是如此。 But there is absolutely no way to do runtime checks for this.但是绝对没有办法对此进行运行时检查。

When at least one entry in an array is given an initializer, any remaining uninitialized entries are initialized to zero.当数组中的至少一个条目被赋予初始化器时,任何剩余的未初始化条目都被初始化为零。 So you can solve the problem by adding a bool to the struct:因此,您可以通过向结构添加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 will be true for the first two entries and false for the rest.前两个条目的valid true ,rest 的false

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM