How to Initialize C++ Structs

How to initialize a struct in accordance with C programming language standards

In (ANSI) C99, you can use a designated initializer to initialize a structure:

MY_TYPE a = { .flag = true, .value = 123, .stuff = 0.456 };

Other members are initialized as zero: "Omitted field members are implicitly initialized the same as objects that have static storage duration." (https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html)

How do I initialize a struct in C

I think there is a typo in the declaration of the data member arr. Instead of

char [3]arr;

you have to write

char arr[3];

You may not initialize an array with empty braces. So write for example

struct {
int a;
char arr[3];
.
.
.
} data = {
.a = 1,
.arr = { 0 }
};

In fact it is enough to write

struct {
int a;
char arr[3];
.
.
.
} data = {
.a = 1
};

The array implicitly will be initialized with zeroes.

Initializing a struct to 0

The first is easiest(involves less typing), and it is guaranteed to work, all members will be set to 0[Ref 1].

The second is more readable.

The choice depends on user preference or the one which your coding standard mandates.

[Ref 1] Reference C99 Standard 6.7.8.21:

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.

Good Read:
C and C++ : Partial initialization of automatic structure

Initialize a struct in C

This should work:

Rectangle world = {"World", {NULL, NULL}, {0, 0}, {5, 5}, 0};

C++ Structure Initialization

If you want to make it clear what each initializer value is, just split it up on multiple lines, with a comment on each:

address temp_addres = {
0, // street_no
nullptr, // street_name
"Hamilton", // city
"Ontario", // prov
nullptr, // postal_code
};

How to initialize a struct to 0 in C++

Before we start:

  1. Let me point out that a lot of the confusion around this syntax comes because in C and C++ you can use the = {0} syntax to initialize all members of a C-style array to zero! See here: https://en.cppreference.com/w/c/language/array_initialization. This works:

    // z has type int[3] and holds all zeroes, as: `{0, 0, 0}`
    int z[3] = {0};

    But, that syntax does not work the same for structs, which are entirely different animals than C-style arrays.

  2. See also my follow-up question I asked after writing this answer below: Why doesn't initializing a C++ struct to = {0} set all of its members to 0?


Back to the answer:

I figured it out: to get it to compile, just delete the zero:

# does NOT work
myStruct _m1 = {0};

# works!
myStruct _m1 = {};

It now compiles. However, I ran a bunch of tests to check some things in my struct_initialization.cpp file in my eRCaGuy_hello_world repo, and that does NOT initialize all elements of the struct to zero! Rather, it initializes the struct to its default values. To run my tests and see for yourself, clone my repo above and run eRCaGuy_hello_world/cpp/run_struct_initialization.sh.

Assuming you have this struct:

typedef struct
{
int num1 = 100;
int num2 = -100;
int num3;
int num4 = 150;
} data_t;

Note: the typedef above is a carry-over from when I was testing this stuff in C instead of C++ (although the default struct values are not allowed in C, of course). For C++, this is preferred instead:

struct data_t
{
int num1 = 100;
int num2 = -100;
int num3;
int num4 = 150;
};

So please ignore it wherever I unnecessarily use typedef to define the structs below.

Anyway, if I declare one of the above data_t structs, and then do this:

data_t d2 = {};
printf("d2.num1 = %i\nd2.num2 = %i\nd2.num3 = %i\nd2.num4 = %i\n\n",
d2.num1, d2.num2, d2.num3, d2.num4);

...the output will be:

d2.num1 = 100
d2.num2 = -100
d2.num3 = 0
d2.num4 = 150

And I'm not even sure if d2.num3 is zero because it was initialized to zero or because it was left uninitialized, and that memory location happened to contain zero.

As explained here: https://en.cppreference.com/w/cpp/language/zero_initialization, you can also do this:

myStruct _m1{};

In the example above, this code:

data_t d2{};
printf("d2.num1 = %i\nd2.num2 = %i\nd2.num3 = %i\nd2.num4 = %i\n\n",
d2.num1, d2.num2, d2.num3, d2.num4);

...would produce output identical to what I showed above.

Even in cases where setting the struct to = {0} DOES work, such as this:

// Does NOT do what I expected! Only sets the FIRST value in the struct to zero! 
// The rest seem to use default values.
data_t d3 = {0};
printf("d3.num1 = %i\nd3.num2 = %i\nd3.num3 = %i\nd3.num4 = %i\n\n",
d3.num1, d3.num2, d3.num3, d3.num4);

...the output is still not what I expected, as it only sets the first value to zero! (I don't understand why):

d3.num1 = 0
d3.num2 = -100
d3.num3 = 0
d3.num4 = 150

On C-style arrays, however (NOT structs), these semantics work fine. Refer to this answer here (How to initialize all members of an array to the same value?). The following lines, therefore, both set all elements of the C-style array to zero when using C++:

uint8_t buffer[100] = {0}; // sets all elements to 0 in C OR C++
uint8_t buffer[100] = {}; // sets all elements to 0 in C++ only (won't compile in C)

So, after much experimentation, it looks like the following several ways are the ONLY ways to zero-initialize a struct, PERIOD. If you know differently, please comment and/or leave your own answer here.

The only ways possible to zero-initialize a struct in C++ are:

  1. Be explicit:

     // C-style typedef'ed struct
    typedef struct
    {
    int num1 = 100;
    int num2 = -100;
    int num3;
    int num4 = 150;
    } data_t;

    // EXPLICITLY set every value to what you want!
    data_t d1 = {0, 0, 0, 0};
    // OR (using gcc or C++20 only)
    data_t d2 = {.num1 = 0, .num2 = 0, .num3 = 0, .num4 = 0};
  2. Use memset() to force all bytes to zero:

     data_t d3;
    memset(&d3, 0, sizeof(d3));
  3. Set all default values to zero in the first place:

     // C-style typedef'ed struct
    typedef struct
    {
    int num1 = 0;
    int num2 = 0;
    int num3 = 0;
    int num4 = 0;
    } data_t;

    // Set all values to their defaults, which are zero in
    // this case
    data_t d4 = {};
    // OR
    data_t d5{}; // same thing as above in C++

    // Set the FIRST value only to zero, and all the rest
    // to their defaults, which are also zero in this case
    data_t d6 = {0};
  4. Write a constructor for the C++ struct

     // 1. Using an initializer list
    struct data
    {
    int num1;
    int num2;
    int num3;
    int num4;

    data() :
    num1(0),
    num2(0),
    num3(0),
    num4(0) {}
    };

    data d7; // all values are zero

    // OR: 2. manually setting the values inside the constructor
    struct data
    {
    int num1;
    int num2;
    int num3;
    int num4;

    data()
    {
    num1 = 0;
    num2 = 0;
    num3 = 0;
    num4 = 0;
    }
    };

    data d8; // all values are zero
  5. Use a struct with no default values, and make your object you create from it static

     typedef struct
    {
    int num1;
    int num2;
    int num3;
    int num4;
    } data_t;

    // `static` forces a default initialization of zero for each
    // value when no other default values are set
    static data_t d9;
  6. So, if you have a struct with non-zero default values, and you want to zero all values, you must do it EXPLICITLY! Here are some more ways:

     // 1. Have a `constexpr` copy of the struct that you use to
    // reset other struct objects. Ex:

    struct data
    {
    int num1 = 1;
    int num2 = 7;
    int num3 = -10;
    int num4 = 55;
    };

    constexpr data DATA_ALL_ZEROS = {0, 0, 0, 0};

    // Now initialize d13 to all zeros using the above `constexpr` struct
    // object
    data d13 = DATA_ALL_ZEROS;

    // OR 2. Use a `zero()` member function to zero the values:

    struct data
    {
    int num1 = 1;
    int num2 = 7;
    int num3 = -10;
    int num4 = 55;

    zero()
    {
    num1 = 0;
    num2 = 0;
    num3 = 0;
    num4 = 0;
    }
    };

    data d14;
    d14.zero();

The big take-away here is that NONE of these: data_t d{}, data_t d = {}, and data_t d = {0}, actually set all members of a struct to zero!

  1. data_t d{} sets all values to their defaults defined in the struct.
  2. data_t d = {} also sets all values to their defaults.
  3. And data_t d = {0} sets only the FIRST value to zero, and all other values to their defaults.

SO, BE EXPLICIT!

Note that the above key take-aways I wrote seem to contradict this documentation on cppreference.com, so it has led me to ask this follow-up question listed just below, which has proven VERY helpful to my understanding!

Going further

  1. MOST USEFUL: Follow-up question of mine: Why doesn't initializing a C++ struct to = {0} set all of its members to 0?

References:

  1. VERY USEFUL:
    1. https://en.cppreference.com/w/cpp/language/zero_initialization
    2. https://en.cppreference.com/w/cpp/language/aggregate_initialization
    3. https://en.cppreference.com/w/cpp/language/value_initialization
  2. VERY USEFUL: Initializing all members of an array (not struct) to the same value:
    1. How to initialize all members of an array to the same value?
    2. [gcc only] How to initialize all members of an array to the same value?
  3. https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/blob/master/cpp/struct_initialization.cpp
    1. Clone this repo and run the code yourself with cpp/run_struct_initialization.sh

Related:

  1. Initializing default values in a struct
  2. *****[my own answer, which demonstrate this sort of struct modification/aggregate member reassignment within any function: leds[0] = {10, 20, 30, 40, 50};] Arduino Stack Exchange: Initializing Array of structs

Initialize values of a struct pointer

You can write a custom constructor:

struct node{
int val;
node* left;
node* right;
node(int);
};

node::node(int _v){
this->val = _v;
this->left = this->right = nullptr;
}

node *root = new node(6); // Works as you want

Or use member initializer list, which looks simpler:

struct node{
int val;
node* left;
node* right;
node(int _v) : val(_v), left(nullptr), right(nullptr) {};
};

Don't forget the braces after the list.

Initialize C struct through a function

You didn't declare a vector, you declared a pointer to a vector. That pointer is uninitialized, so attempting to dereference it invokes undefined behavior.

Create a struct Vector and pass its address:

struct Vector vec;
initialize_vector(&vec);
printf("%d\n", vec.length);

If you want to allocate space for a struct Vector at the same time, change the function to call malloc and return the pointer:

struct Vector *initialize_vector()
{
struct Vector *vector = malloc(sizeof(*vector));
if (!vector) {
perror("malloc failed");
exit(1);
}
vector->elements = NULL;
vector->length = 0;
return vector;
}

...

struct Vector *vector = initialize_vector();

How do I initialize a struct containing another struct?

How do I initialize a struct containing another struct?

There are several ways to initialize a struct. To simplify, the following example uses smaller structs than those you provided...

The following will illustrate initialization with initialization with values ( = {,,,{,,}}; ), then with zeros = {0} :

typedef struct {
int count;
float cash;
char item[50];
}Purchase;

typedef struct {
int accnt;
char acct_name[50];
Purchase purch;
} Acct;

Acct acct = {100123, "Robert Baily", {15, 12.50, "Tires"}};
//Or, using member names to self document the initialization statement as suggested in comments:
Acct acct1 = Acct acct = {.accnt=100123, .acct_name="Robert Baily", {.count=15, .cash=12.50, .item="Tires"}};

Acct acct2 = {0};

int main(void)
{
printf("acct = %d\nAcct_name = %s\nitem = %s\ncount = %d\ncash = %3.2f\n", acct.accnt, acct.acct_name, acct.purch.item, acct.purch.count, acct.purch.cash);
printf("acct2 = %d\nAcct_name = %s\nitem = %s\ncount = %d\ncash = %3.2f\n", acct2.accnt, acct2.acct_name, acct2.purch.item, acct2.purch.count, acct2.purch.cash);
return 0;
}

Although these are small, they illustrate what you are doing with your larger, more complicated structs. I suggest that for your structs it will be extremely tedious, and probably not necessary to use the first method. struct declaration in an actual program is often initialized by zeroing. i.e. {0}

Initialize a struct with struct types inside

You can use nested {}.

struct person
{
struct name fullName;
struct address fullAddress;
int age;
} person =
{
{
"First Name", /* person.fullName.firstName */
"Last Name", /* person.fullName.lastName */
},
{
"Street", /* person.fullAddress.street */
42 /* person.fullAddress.number */
},
42 /* person.age */
};

Then you can access to the other members as follow:

person.fullName.firstName;
person.fullName.lastName;
person.fullAddress.street;
person.fullAddress.number;
person.age;


Related Topics



Leave a reply



Submit