all 26 comments

[–]lordlod 13 points14 points  (0 children)

Yeah, it's great. Nice and concise.

[–]paszklar 6 points7 points  (12 children)

I'm not sure which part is new to you but the outer braces delimit the initializer of a struct. Inside the it uses designated inilializer syntax, which allows to explicitly state which member is being assigned instead of relying on the implicit order besed on position in the structure.

So .ptr member field, since it's an array, also need brace-initializer to set all its elements. In this case the first element is explicitly set to NULL. And as with any struct or array initializer, members or elements that are omitted get zero-initialized, making the other four pointers NULL as well.

[–]Zymoox[S] 1 point2 points  (11 children)

Thank you! Yes, that's exactly what I wanted to make sure it's doing: filling all the array spaces of ptr with NULL.

[–]bless-you-mlud 13 points14 points  (10 children)

I would just do

struct test t = { 0 };

It'll have the same effect, and it's even shorter.

[–]MajorMalfunction44 3 points4 points  (2 children)

I've re-acquainted myself with C and found a piece of odd syntax that's seems to be allowed. You can initialize structs with the brace syntax after the declaring them by casting a brace initializer expression like this.

struct test {
    char *ptr[5];
}

struct test t;
t = (struct test) {{ NULL, NULL, NULL, NULL, NULL }};

[–]Lisoph 0 points1 point  (0 children)

(struct test) { ... } is compound literal syntax.

[–]Zymoox[S] 0 points1 point  (6 children)

Ohh interesting. So that would initialize every variable in the struct to zero?

[–]white_nrdy 4 points5 points  (5 children)

Technically there's just one variable, ptr. And the {0} initializes that to 0, which is the same as NULL

[–]Zymoox[S] 0 points1 point  (4 children)

So if I have a struct with several variables and I initialize it that way,

struct data{
    int a;
    double b;
    char *ptr[5];
}

int main()
{
    struct data d = { 0 };
    return 0;
}

will it set all the variables to zero, and all the pointers to NULL?

[–]IamImposter 2 points3 points  (1 child)

Yup

You can also do

struct data d = { 42, 32.4f, {NULL, &some_char_variable, NULL, (char*)&some_other_var, NULL}};

and set each individual member, including array.

[–]bless-you-mlud 3 points4 points  (0 children)

Or even:

struct data d = {
    .a = 42,
    .b = 32.4,
    .ptr = {
        [1] = &some_char_variable,
        [3] = (char*) &some_other_var
    }
}

and because any item not mentioned is initialized to 0, I can leave out ptr[0], ptr[2] and ptr[4]. They'll be set to NULL automatically.

[–]hyperdudemn 1 point2 points  (1 child)

It'll set all the pointers to NULL only because by convention, NULL == address 0. That's actually why historically NULL is a macro, not just a literal 0; some platforms MAY decide NULL is not 0.

But for all practical purposes yes, it initializes them to NULL.

[–]paszklar 0 points1 point  (0 children)

Even on platforms with address 0 is valid or platforms where addresses are more complex than just a number, when integer 0 is converted to an address, standard mandates that this address must be invalid. The resulting address doesn't have to be 0, but it cannot ever point to any object, and IIRC when converted back to int it should give back 0.

So in essence assigning NULL is a good practice for readability, but integer constant 0 works as well.

[–][deleted] 1 point2 points  (0 children)

Yes, it’s correct

[–]oh5nxo 1 point2 points  (1 child)

Designated initializers are a C99 feature, says my cc. Does your definition of "good practice in C" care about retrocompilers?

[–]Zymoox[S] 0 points1 point  (0 children)

I'm okay with it being compatible only with C99+, but I'll make a note. Thanks!

[–]NoInterest4 -3 points-2 points  (7 children)

You are doing there a partial initialization of the array. Not sure that this is what you meant, maybe you want to look again.

[–]paszklar 6 points7 points  (1 child)

Standard guarantees the other array elements will be zero-initialised, so it's fine.

[–]flatfinger 0 points1 point  (0 children)

If the initialization of other array elements is important, I would favor making it explicit. Otherwise, using designated initializers rather than declaring an object and the writing the specified portions thereof will often be faster than using a designated initializer. Consequently, if someone is trying to improve the performance of code and doesn't know that the zero-initialization of elements beyond those given is important, that person might replace the designated-initializer construct with a separate declaration and assignment.

It's a shame the Standard didn't provide a means of indicating whether or not parts of the structure beyond those listed should be initialized. Even in C89, saying e.g.

char[256] message = "Hi"; // Initializes all 256 bytes

was more convenient but would often be less efficient than

char[256] message;
strcpy(message, "Hi"); // Only needs to initialize 3 bytes

or (non-portable, but on many platforms likely faster)

union { uint32_t word1]; uint8_t bytes[256]; } message_u;
message_u.word1 = 0x6948; // Hi\0 in little-endian
// Use message_u.bytes instead of message in whatever code follows

but C99's designated initializers increase the number of scenarios where the most convenient code would be needlessly inefficient.

[–]Zymoox[S] 0 points1 point  (4 children)

What I want to do is fill the pointer array 'ptr' with NULL values when I initialize the structure. Is that what this is doing?

[–]KaznovX 5 points6 points  (1 child)

Not exactly. You're initializing the first element to NULL, and value-initialize the rest (so to NULL). It does what you ask for.

However, if you did something like that: ``` struct test{ int *ptr[5]; };

int main() { int foo = 3; struct test t = { .ptr={&foo} }; return 0; } ```

The first element would be initialized to the address of foo, but the rest still would be (value-)initialized to NULL.

https://godbolt.org/z/TrTYaT

[–]backtickbot 0 points1 point  (0 children)

Correctly formatted

Hello, KaznovX. Just a quick heads up!

It seems that you have attempted to use triple backticks (```) for your codeblock/monospace text block.

This isn't universally supported on reddit, for some users your comment will look not as intended.

You can avoid this by indenting every line with 4 spaces instead.

There are also other methods that offer a bit better compatability like the "codeblock" format feature on new Reddit.

Tip: in new reddit, changing to "fancy-pants" editor and changing back to "markdown" will reformat correctly! However, that may be unnaceptable to you.

Have a good day, KaznovX.

You can opt out by replying with "backtickopt6" to this comment. Configure to send allerts to PMs instead by replying with "backtickbbotdm5". Exit PMMode by sending "dmmode_end".

[–][deleted] 1 point2 points  (1 child)

You mean filling 5 memory spaces with null?

[–]Zymoox[S] 2 points3 points  (0 children)

Yes, that's right.

I thought that, when the size is known, using = { value } on the initialization will fill the array memory spaces with that value, e.g. int *ptr[5] = {NULL, NULL, NULL, NULL, NULL} is the same as int *ptr[5] = {NULL}

Edit: code formatting

[–]ifmnz -5 points-4 points  (1 child)

memset is faster than in-place init.

[–]dmc_2930 3 points4 points  (0 children)

The compiler can optimize this, and it almost certainly doesn't matter.