2

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?

7
  • 1
    Unit tests? The compiler really doesn't care since it trusts you know what you're doing. Commented Oct 15, 2019 at 21:53
  • 2
    In your code above, all of array a other than the parts you set explicitly will be initialized to all zero bits. So you can easily check that a[2].x[0] == '\0', or that a[3].y == 0, for example. Commented Oct 15, 2019 at 21:56
  • Of course it does. The problem isn't that the compiler is complaining, rather that i wanna know how to check it in a running program, if it's even possible. Commented Oct 15, 2019 at 21:57
  • C has no way of doing runtime checks on whether an object is initialized or not. Commented Oct 15, 2019 at 21:59
  • 1
    @vMysterion I assume you meant to write char x[20] instead of char[20] x? Commented Oct 15, 2019 at 23:03

2 Answers 2

4

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.

Sign up to request clarification or add additional context in comments.

3 Comments

Sure there are ways to detect initialization. You just have to implement them yourself as in user3386109's answer. I think the way you worded that first sentence is a bit misleading.
@CareyGregory Yes, I was editing when you wrote the comment.
That's pretty much what i did now. I simply said there can't be a value of 0 in the int variable and then i simply checked every struct on the variable and if it's 0. If it is, it is uninitialized.
2

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.

4 Comments

That's a pretty good suggestions - but to me this kinda feels more like a workaround rather than a solution.
@vMysterion There is no solution. Well, except for learning how initialization works.
@vMysterion C is a straightforward language. It only does what you tell it to do. In particular, an array in C is just a block of memory that holds the information that you put in it. There is no controlling object that contains additional information about the array, as you might find in C++ vectors, or Python lists.
@vMysterion In C that's definitely a solution, and a commonly used one at that.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.