Difference in Initializing and Zeroing an Array in C/C++

Difference in initializing and zeroing an array in c/c++?

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).

How to initialize array to 0 in C?

Global variables and static variables are automatically initialized to zero. If you have simply

char ZEROARRAY[1024];

at global scope it will be all zeros at runtime. But actually there is a shorthand syntax if you had a local array. If an array is partially initialized, elements that are not initialized receive the value 0 of the appropriate type. You could write:

char ZEROARRAY[1024] = {0};

The compiler would fill the unwritten entries with zeros. Alternatively you could use memset to initialize the array at program startup:

memset(ZEROARRAY, 0, 1024);

That would be useful if you had changed it and wanted to reset it back to all zeros.

Why would my array would be filled out to zero, when I initialised it to -1

Because that's how array initialization works in C++. You set the first element of the array memo to -1, and the compiler will value-initialize (before the C++11 standard) or default-initialize (since C++11 and onward) all of of the other elements.

Please read more about aggregate initialization here.

Initializing an array of zeroes

The empty braced initialisation performs aggregation-initialization of the array: this leads to zero-initialization of the int elements.

Yes, this is guaranteed.

How to initialize all members of an array to the same value?

Unless that value is 0 (in which case you can omit some part of the initializer
and the corresponding elements will be initialized to 0), there's no easy way.

Don't overlook the obvious solution, though:

int myArray[10] = { 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 };

Elements with missing values will be initialized to 0:

int myArray[10] = { 1, 2 }; // initialize to 1,2,0,0,0...

So this will initialize all elements to 0:

int myArray[10] = { 0 }; // all elements 0

In C++, an empty initialization list will also initialize every element to 0.
This is not allowed with C until C23:

int myArray[10] = {}; // all elements 0 in C++ and C23

Remember that objects with static storage duration will initialize to 0 if no
initializer is specified:

static int myArray[10]; // all elements 0

And that "0" doesn't necessarily mean "all-bits-zero", so using the above is
better and more portable than memset(). (Floating point values will be
initialized to +0, pointers to null value, etc.)

How all the elements of array initialize to zero and first element to 1 in c

The array elements are initialized based on the initialization rule for aggregate type with initialization lists, as specified in C standard.

It mentions, if there are less number of initializers supplied in the brace-enclosed list than that of the number of element in the aggregate type, the remaining elements in the aggregate type will be initialized with the value as if they have static storage duration, i.e., a value of 0.

To quote C11, chapter §6.7.9, Initialization (emphasis mine)

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.

and regarding the initialization of variables having static storage duration,

[..] If an object that has static or thread storage duration is not initialized
explicitly, then:

  • [...]
  • if it has arithmetic type, it is initialized to (positive or unsigned) zero;
  • [...]

So, very rightly, in your case

  int arr[10]={1};

arr[0] is having a value 1, arr[1] to arr[9] all are set to 0.

About initialize array with zero

Because n is defined as a variable, there are two problems with the following statement:

int arr[n]={ };

The error on my system states

error: use of GNU empty initializer extension

If this were not a VLA, the problem could be addressed by providing an initializer:

#define n 10 //used to size a non-VLA array
...
int arr[n]={0}; //Uses constant array size, not variable, thus can be initialized normally.

But it is a VLA, leading to the next issue, incorrect use of VLA, where the error states:

error: variable-sized object may not be initialized

Both issues can be addressed with following:

int arr[n];
memset(arr, 0, sizeof(arr));

One final suggestion is to check the return value for the scanf() statement:

scanf("\n%d %d",&n,&m);

To ensure the correct number of items have been processed before assuming n.

int count = scanf("\n%d %d",&n,&m);
if(count == 2)
{
int arr[n];
memset(arr, 0, sizeof(arr);
....


Related Topics



Leave a reply



Submit