position of struct variable declaration and list initializer

Hi, when learning struct, I found that the position of the variable declaration and list initializer can have very different results.

First, this code won't compile:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
  #include <iostream>
#include <string>

using namespace std;

struct Employee
{
	short id;
	int age;
	double wage;
};

Employee yam[5];
yam[0].age = 30;
yam[3].id = 40;
yam[4].wage = 90;

int main()
{
	for (int n = 0; n < 5; n++)
	{
		cout << yam[n].age << ' ' << yam[n].id << ' ' << yam[n].wage << endl;
	}

	cin.get();
}


This second code is when both the variable declaration and list initializer are moved inside of main function. It compiles, but the non-specified values in the list are garbage:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
#include <string>

using namespace std;

struct Employee
{
	short id;
	int age;
	double wage;
};




int main()
{
	Employee yam[5];
	yam[0].age = 30;
	yam[3].id = 40;
	yam[4].wage = 90;
	for (int n = 0; n < 5; n++)
	{
		cout << yam[n].age << ' ' << yam[n].id << ' ' << yam[n].wage << endl;
	}

	cin.get();
}


Finally, in the code below, the variable declaration has global scope, and the list initializers are within main function. This gives zeros of the un-defined values in the list:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include <iostream>
#include <string>

using namespace std;

struct Employee
{
	short id;
	int age;
	double wage;
};

Employee yam[5];


int main()
{
	
	yam[0].age = 30;
	yam[3].id = 40;
	yam[4].wage = 90;
	for (int n = 0; n < 5; n++)
	{
		cout << yam[n].age << ' ' << yam[n].id << ' ' << yam[n].wage << endl;
	}

	cin.get();
}


Can someone please explain what the position/scope do to the entire program? Thanks.
Let's simply things a little bit:
1
2
3
4
5
6
7
8
9
10
11
12
#include <iostream>

int global_var;

int main() {
    static int static_var;
    int normal_var;

    std::cout << global_var << "\n"; // always 0
    std::cout << static_var << "\n"; // always 0
    std::cout << normal_var << "\n"; // undefined behaviour!
}


Why? What's happening?

Well, basically, in C++ if you don't initialize a variable to something it undergoes what's called "default initialization" (see https://en.cppreference.com/w/cpp/language/default_initialization for lots of details). Default initialization for non-class types results in, well, "something". In essence, that's what's happened to normal_var — default initializing for a normal type like int could result in anything.

But what about global_var and static_var? Well, C++ also says that variables with "static storage duration"; in other words, globals, static variables, thread local variables, and so forth, get zero initialized before any other initialization happens (again, see https://en.cppreference.com/w/cpp/language/zero_initialization for lots of details). Then when they get default initialized, nothing happens and they stay 0.

In your example, when you defined yam globally it got zero-initialized first, so it got filled with 0s. However, when you defined yam inside a function, it did not get zero-initialized, and was instead filled with junk.
Last edited on
Code (1) is illegal simply because you can't do logic like making assignments outside of a function scope (lines 14-16).

Code (2) is undefined behavior because you have uninitialized values. You don't initialize yam[1], [2] at all, and you don't initialize yam[0].id/wage, yam[3].age/wage, yam[4].id/age. So you most likely get garbage values in those values.

Code (3) avoids the undefined behavior for uninitialized variables because when you declare something at a global scope (line 13), it is auto-initialized to 0 implicitly.

That being said, global variables should generally be avoided. You should use Code (2), but make sure you initialize all the values in your yam array before using them or printing them.
Last edited on
Topic archived. No new replies allowed.