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.
aother than the parts you set explicitly will be initialized to all zero bits. So you can easily check thata[2].x[0] == '\0', or thata[3].y == 0, for example.char x[20]instead ofchar[20] x?