Home > Articles > Programming > C/C++

C++ Reference Guide

Hosted by

Toggle Open Guide Table of ContentsGuide Contents

Close Table of ContentsGuide Contents

Close Table of Contents

POD Initialization

Last updated Jan 1, 2003.

Unlike auto objects which are automatically initialized by their constructor, auto variables have an indeterminate (i.e., garbage) value by default. Explicit initialization of such variables eliminates unpleasant surprises at runtime and ensures that your code always behaves consistently. I will show how to explicitly initialize all sorts of automatic data: scalar types, pointers, arrays, structs and unions.

Built-in Types

Initialization of a built-in type (int, bool and double etc.) looks like an assignment expression: an assignment operator and an initializer appear after the variable's name. The only difference between plain assignment and an initialization is that the latter must appear in the variable's declaration. For example:

int func()
{
int val=100;
double price=99.99;
bool isopen=false;
Person *p=NULL;
//...
}

Each initializer is of the same type as the variable it initializes. As a special case, C++ allows you to use the literal 0 as a universal initializer</a> for all built-in types, including pointers, pointers to functions and pointers to members. Therefore, you may initialize isopen like this:

bool isopen=0; // 0 is converted to 'false'

Similarly, all pointer types may be initialized like this:

Person *p=0; //converted to NULL
void (*pf)(int)=0; //pointer to function
void (A::*pmf)(int)=0; //pointer to member function

In fact, C++ pundits advocate the use of 0 instead of NULL in pointer initializations as it will save you the trouble of #including a header file.

Arrays

As noted earlier, assignment and initialization look syntactically the same. Yet there are two major differences between the two. Conceptually, initializations are performed at compile time whereas assignments take place at runtime. More importantly, you may initialize an array or an aggregate (I will discuss aggregates shortly) but you can't assign to them:

char passenger[10]="Phileas"; //OK, initialization
char passenger2[10];
passenger2 = "Fix"; //error: array assignment is illegal

If you provide fewer initializers than the number of elements that an array has, all remaining elements will be default-initialized. For example, in the following expression the array set has five elements but only the first three have explicit initializers:

int set[5]={0,1,2};

The elements set[4] and set[5] are implicitly initialized to 0 in this case. Therefore, if you wish to zero-initialize a large array, simply provide a single initializer and let the compiler take care of the rest:

double scores[500]={0.0}; //remaining 499 elements
      //are initialized to 0.0 as well

The following declaration is equivalent because the literal 0 is implicitly converted to the type of the initialized object, i.e., 0.0:

double scores[500]={0};

Likewise, if you're using a char array:

char URL[2048]={0}; //all elements are initialized to '\0'

Notice how awkward and error prone a memset()-based "initialization" looks in comparison:

#include <cstring>
char URL[2048];
memset(URL, 0, 2048);

Not only do you need to #include a special header but you also must specify the array's size. Worse yet, programmers might confuse between the second and third arguments:

int arr[100];
memset (arr, 100, 0); //bad! actually meant (arr, 0, 100)

To the programmer's surprise, arr's elements will contain garbage values at runtime.

Aggregates

An aggregate is a Plain Old Data(POD) struct, class or union, or an array of POD elements (as well as arrays of built-in types). To initialize a POD struct, provide one or more initializers in curly braces. If there are fewer initializers than the number of members, the remaining members are default-initialized:

struct employee
{
 int age;
 char [20] name;
 char[100] address;
 char occupation[50];
};
employee emp={45, "Passepartout", "Saville Row"};

The array occupation is zero-initialized since no explicit initializer was provided for it. You can easily zero initialize all the members of a struct like this:

employee e={0};

You're probably wondering whether this would work if the first member weren't a scalar type. For example,

struct Book
{
 char[100] title;
 char [100] author;
 int pages;
};

Yes, it would:

Book b={0}; 

This works because aggregate initialization rules are recursive; the initializer 0 is initializes the first Book member, which is an array. As you already know, if an array's initialization list contains fewer initializers than the number of its elements, the remaining elements are zero-initialized. Thus, the literal 0 initializes the first element of the array title, letting the compiler zero-initialize all the remaining elements. Because b's initialization list doesn't provide explicit initializers for the members author and pages, they are all zero-initialized as well. Neat, isn't it?

Suppose we want to declare an array of Book objects. The same form of initialization will work here too:

Book arr[20] ={0};

Even if you change the definition of struct Book later (by adding more data members to it, for example) or if you change the size of the array b, the ={0}; initializer will properly initialize every element thereof.

Unions

Union initialization is similar to struct initialization except that it may include only a single initializer. This initializer must initialize the first union member. C++ guarantees that if the rest of the members are larger than the first, they're zero-initialized as well:

union U
{ 
 int a; 
 char b[4]; 
};

U a = { 1 }; //fine

U b = a; //fine

U c = 1; // error

U d = { 0, "abc" }; // error

U e = { "abc" }; // error

Summary

Initializing auto variables is good programming practice. Of course, you don't have to initialize all variables to zero. However, you shouldn't leave auto varaibles uninitialized. A partial initialization list initializes the entire aggregate; members for which no explicit initializer is provided are default initialized. Unions are a special case -- only their first member can be initialized.