Say I want to initialize myArray
char myArray[MAX] = {0};
char myArray[MAX] = {0,};
char myArray[MAX]; memset(myArray, 0, MAX);
Are they all equal or any preferred over another?
Thank you
arraysc++initialization
Say I want to initialize myArray
char myArray[MAX] = {0};
char myArray[MAX] = {0,};
char myArray[MAX]; memset(myArray, 0, MAX);
Are they all equal or any preferred over another?
Thank you
The important difference is that the first default initializes the array in an element-specific manner: Pointers will receive a null pointer value, which doesn't need to be 0x00 (as in all-bits-zero), booleans will be false. If the element type is a class type that's not a so-called POD (plain old data-type), then you can only do the first one, because the second one only works for the simplest cases (where you don't have virtual functions, user defined constructors and so on). In contrast, the second way using the memset sets all elements of the array to all-bits-zero. That is not always that what you want. If your array has pointers for example, they won't be set to null-pointers necessarily.
The first will default initialize the elements of the array, except for the first one, which is set to 0 explicitly. If the array is local and on the stack (that is, not a static), the compiler internally often does a memset to clear the array out. If the array is non-local or static, the first version can be considerably more efficient. The compiler can put the initializers already, at compile time, into the generated assembler code, making it require no runtime code at all. Alternatively, the array can be laid out on a section that is automatically zero'd out (also for pointers, if they have a all-bits-zero representation) when the program starts in a fast manner (i.e page-wise).
The second does a memset explicitly over the whole array. Optimizing compilers will usually replace a memset for smaller regions with inline machine code that just loops using labels and branches.
Here is assembler-code generated for the first case. My gcc stuff isn't much optimized, so we got a real call to memset (16 bytes at the stack-top are always allocated, even if we got no locals. $n is a register number):
void f(void) {
int a[16] = { 42 };
}
sub $29, $29, 88 ; create stack-frame, 88 bytes
stw $31, $29, 84 ; save return address
add $4, $29, 16 ; 1st argument is destination, the array.
add $5, $0, 0 ; 2nd argument is value to fill
add $6, $0, 64 ; 3rd argument is size to fill: 4byte * 16
jal memset ; call memset
add $2, $0, 42 ; set first element, a[0], to 42
stw $2, $29, 16 ;
ldw $31, $29, 84 ; restore return address
add $29, $29, 88 ; destroy stack-frame
jr $31 ; return to caller
The gory details from the C++ Standard. The first case above will default-initialize remaining elements.
8.5
:
To zero-initialize storage for an object of type T means:
- if T is a scalar type, the storage is set to the value of 0 (zero) converted to T;
- if T is a non-union class type, the storage for each nonstatic data member and each base-class subobject is zero-initialized;
- if T is a union type, the storage for its first data member is zero-initialized;
- if T is an array type, the storage for each element is zero-initialized;
- if T is a reference type, no initialization is performed.
To default-initialize an object of type T means:
- if T is a non-POD class type, the default constructor for T is called
- if T is an array type, each element is default-initialized;
- otherwise, the storage for the object is zero-initialized.
8.5.1
:
If there are fewer initializers in the list than there are members in the aggregate, then each member not explicitly initialized shall be default-initialized (8.5).
int* primes = new (nothrow) int[amount];
is using default-initialization, which for scalars like int
is a noop (i.e. no actual initialization is performed).
If you want explicit initialization, use value-initialization instead:
int* primes = new (nothrow) int[amount]();
From the C++11 standard, §8.5/6:
To default-initialize an object of type
T
means:
- if
T
is a (possibly cv-qualified) class type, the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);- if
T
is an array type, each element is default-initialized;- otherwise, no initialization is performed.
If a program calls for the default initialization of an object of a const-qualified type
T
,T
shall be a class type with a user-provided default constructor.
§8.5/7:
To value-initialize an object of type
T
means:
- if
T
is a (possibly cv-qualified) class type with a user-provided constructor, then the default constructor forT
is called (and the initialization is ill-formed if T has no accessible default constructor);- if
T
is a (possibly cv-qualified) non-union class type without a user-provided constructor, then the object is zero-initialized and, ifT
’s implicitly-declared default constructor is non-trivial, that constructor is called.- if
T
is an array type, then each element is value-initialized;- otherwise, the object is zero-initialized.
An object that is value-initialized is deemed to be constructed and thus subject to provisions of this International Standard applying to “constructed” objects, objects “for which the constructor has completed,” etc., even if no constructor is invoked for the object’s initialization.
§8.5/6:
To zero-initialize an object or reference of type
T
means:
- if
T
is a scalar type, the object is set to the value0
(zero), taken as an integral constant expression, converted toT
;- if
T
is a (possibly cv-qualified) non-union class type, each non-static data member and each base-class subobject is zero-initialized and padding is initialized to zero bits;- if
T
is a (possibly cv-qualified) union type, the object’s first non-static named data member is zero-initialized and padding is initialized to zero bits;- if
T
is an array type, each element is zero-initialized;- if
T
is a reference type, no initialization is performed.
And finally from §8.5/10:
An object whose initializer is an empty set of parentheses, i.e.,
()
, shall be value-initialized.
(All emphasis mine.)
Best Answer
Actually, in C++, I personally recommend:
They all do the same thing, but I like this one better in C++; it's the most succinct. (Unfortunately this isn't valid in C.)
By the way, do note that
char myArray[MAX] = {1};
does not initialize all values to 1! It only initializes the first value to 1, and the rest to zero. Because of this, I recommend you don't writechar myArray[MAX] = {0};
as it's a little bit misleading for some people, even though it works correctly.