vMysterion
vMysterion

Reputation: 185

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?

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?

Upvotes: 2

Views: 1877

Answers (2)

klutt
klutt

Reputation: 31379

Solutions to your problem

Note that it depends a bit on what you actually mean with initialized. In your example, the whole array is indeed initialized as far as the C standard is concerned. 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. 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. 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.

Separate Boolean field

You could do as user3386109 did in their answer and add a separate Boolean field.

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. 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. 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

This is what the standard says:

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.

We can also read this:

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. Let's see what the standard has to say about that.

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:

  • if it has pointer type, it is initialized to a null pointer;
  • 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. Even for arrays of structs containing an enum and a union. But there is absolutely no way to do runtime checks for this.

Upvotes: 4

user3386109
user3386109

Reputation: 34829

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:

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.

Upvotes: 2

Related Questions