I have an assignment that requires me to understand what are designated initializers in C, and what it means to initialize a variable with one.
I am not familiar with the term and couldn't find any conclusive definitions.
What is a designated initializer in C?
Designated initialisers come in two flavours:
1) It provides a quick way of initialising specific elements in an array:
int foo[10] = { [3] = 1, [5] = 2 };
will set all elements to foo to 0, other than index 3 which will be set to 1 and index 5 which will be set to 2.
2) It provides a way of explicitly initialising struct members. For example, for
struct Foo { int a, b; };
you can write
struct Foo foo { .a = 1, .b = 2 };
Note that in this case, members that are not explicitly initialised are initialised as if the instance had static duration.
Both are standard C, but note that C++ does not support either (as constructors can do the job in that language.)
The Designed Initializer came up since the ISO C99 and is a different and more dynamic way to initialize in C when initializing struct, union or an array.
The biggest difference to standard initialization is that you don't have to declare the elements in a fixed order and you can also omit element.
From The GNU Guide:
Standard C90 requires the elements of an initializer to appear in a fixed order, the same as the order of the elements in the array or structure being initialized.
In ISO C99 you can give the elements in random order, specifying the array indices or structure field names they apply to, and GNU C allows this as an extension in C90 mode as well
Examples
1. Array Index
Standard Initialization
int a[6] = { 0, 0, 15, 0, 29, 0 };
Designed Initialization
int a[6] = {[4] = 29, [2] = 15 }; // or
int a[6] = {[4]29 , [2]15 }; // or
int widths[] = { [0 ... 9] = 1, [10 ... 99] = 2, [100] = 3 };
2. Struct or union:
Standard Initialization
struct point { int x, y; };
Designed Initialization
struct point p = { .y = 2, .x = 3 }; or
struct point p = { y: 2, x: 3 };
3. Combine naming elements with ordinary C initialization of successive elements:
Standard Initialization
int a[6] = { 0, v1, v2, 0, v4, 0 };
Designed Initialization
int a[6] = { [1] = v1, v2, [4] = v4 };
4. Others:
Labeling the elements of an array initializer
int whitespace[256] = { [' '] = 1, ['\t'] = 1, ['\h'] = 1,
['\f'] = 1, ['\n'] = 1, ['\r'] = 1 };
write a series of ‘.fieldname’ and ‘[index]’ designators before an ‘=’ to specify a nested subobject to initialize
struct point ptarray[10] = { [2].y = yv2, [2].x = xv2, [0].x = xv0 };
Guides
designated-initializers-c | geeksforgeeks.org
using-designated-initializers
tutorialspoint.com | designated-initializers-in-c
Related
This question already has answers here:
Using non standard declaration of array in C
(2 answers)
Closed 6 years ago.
Here is one not-so-common way of initializing the array:
int a[3] = {[2] 5, [0] 10, [1] 15};
Used this array in the program,
#include <stdio.h>
int main() {
//code
int a[3] = {[2] 5, [0] 10, [1] 15};
printf("a[0] = %d a[1] = %d a[2] = %d\n", a[0], a[1], a[2]);
return 0;
}
Output:
a[0] = 10 a[1] = 15 a[2] = 5
Online Compiler Link:
http://code.geeksforgeeks.org/4onQAI
So, I have a question:
Is it the correct way to initialize array?
Close. The correct way is as follows:
int a[3] = {[2] = 5, [0] = 10, [1] = 15};
This is a designated initializer, which allows you to initialize specified elements. Any elements not specified are set to 0.
This is specified in section 6.7.9 of the C standard.
The syntax you show is a non-standard extension supported by some compilers, specifically GCC. If you were to compile with -pedantic, you would get the following warning:
warning: obsolete use of designated initializer without ‘=’
Your code snippet uses an obsolete syntax for this designated initializer:
int a[3] = {[2] = 5, [0] = 10, [1] = 15};
An alternative syntax for this that has been obsolete since GCC 2.5 but GCC still accepts is to write ‘[index]’ before the element value, with no ‘=’. (reference)
Omitting = is not standard, and should not be used for new development.
The correct way to use designated initializer is
int a[3] = {[2] = 5, [0] = 10, [1] = 15};
There should be = between the [index] and the value as per the C standard.
The way you are initialising may the some extension.
Grammer for initializations(C11-§6.7.9)
initializer:
assignment-expression
{ initializer-list }
{ initializer-list , }
initializer-list:
designationopt initializer
initializer-list , designationopt initializer
designation:
designator-list =
designator-list:
designator
designator-list designator
designator:
[ constant-expression ]
. identifier
what will be the dimension of integer array arr if declared like this :
int arr[][2]={1,2,3};
what is the use of not declaring the highest dimension ?
Somewhat to my surprise, your declaration:
int arr[][2]={1,2,3};
appears to be legal. You can legally omit inner braces in initializers. For example, if you wanted to define the bounds of arr explicitly and initialize all its elements, you could write either:
int arr[2][2] = { { 1, 2}, { 3, 4 } };
or, equivalently:
int arr[2][2] = { 1, 2, 3, 4 };
You can also omit trailing elements, and they'll be implicitly set to zero. For a one-dimensional array, this is straightforward; this:
int arr[4] = { 1, 2, 3 };
is equivalent to:
int arr[4] = { 1, 2, 3, 0 };
And if you omit a dimension, it can be inferred from the initializer:
int arr[] = { 1, 2, 3, 4 }; // 4 elements
Since you're defining arr as an array of 2-element arrays of int, this:
int arr[][2]={1,2,3};
is equivalent to this:
int arr[][2] = { { 1, 2 }, { 3 } };
You have two elements in the initializer (each of which initializes a 2-element array), so that's equivalent to:
int arr[2][2] = { { 1, 2 }, { 3 } };
Finally, you've omitted the last initializer sub-element, so it's implicitly zero:
int arr[2][2] = { { 1, 2 }, { 3, 0 } };
In general, omitting dimensions and trailing initializers is useful because it lets the compiler figure out certain things. If I write:
char message[] = "hello, world";
I don't have to count the characters in the string (and add 1 for the terminating '\0'). Computers are really good at counting things; making a human do that job would be silly.
Similarly, omitting some initializers lets you provide only the information you need. With C99's addition of designated initializers, you can even initialize a specified member of a structure and let the compiler take care of everything else:
struct foo obj = { .something = 42 };
As for flattening initializers by omitting inner curly braces, I personally don't see much use for that except for the special case of using a { 0 } initializer to initialize and entire array or structure to zero. In particular, for multidimensional arrays I find it much clearer to show the entire structure of the array.
Per the minimal bracketing rule (6.7.9p20 in C11),
enough initializers from the list are taken to account for the elements or members of the subaggregate or the first member of the contained union; any remaining initializers are left to initialize the next element or member of the aggregate of which the current subaggregate or contained union is a part.
So the following declarations are equivalent:
int arr[][2]={1,2,3};
int arr[][2]={{1,2},{3}};
int arr[2][2]={{1,2},{3}};
As to why this is useful: when initializing a large multi-dimensional array, it may well be obvious to the reader how many items there are per subaggregate; in which case, there is no need to supply the brackets between subaggregates.
What is the meaning of this initialization:
char arr[10] = { 0, };
I'm familiar with char arr[10] = {0}; which sets all the elements to zero, and with char arr[10] = {1,2}; which sets the first two elements to 1 and 2 (ascii) and the rest to 0.
I'm not familiar with the format above.
A quick test showed that it's probably just like char arr[10] = {0};, but is there other meaning I'm not aware of?
From How to initialize all members of an array to the same value?:
Initialize all members to the same value:
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:
int myArray[10] = {}; //all elements 0 in C++
Objects with static storage duration will initialize to 0 if no initializer is specified:
static int myArray[10]; //all elements 0
If your compiler is GCC you can use following syntax:
int array[1024] = {[0 ... 1023] = 5};
int A[10] = {[0 ... 4] = 5, [5 ... 9] = 3};
Yes, it's equivalent with the version without the trailing comma.
See this question for more discussion about trailing commas.
As standard
A trailing comma may appear after the last expression in an array initializer and is ignored
char arr[10] = { 0, }; and char arr[10] = {0} is same in this case.
But char arr[10] = {5, } is different. 5 will be stored in a[0] and remaining will be filled with zero.
I suggest not to use this for global variables, because it will increase the data section size.
There is no difference between int arr[3] ={0,}; and int arr[3] ={0};.
Ref: C11 6.7.9:
initializer:
assignment-expression
{ initializer-list }
{ initializer-list , }
Both forms of initializer lists are considered initializers. The form with the comma at the end is preferred by many because it makes it easier to rearrange or add elements to the list during code maintenance.
int arr[3] ={0,};
declares an array of three elements and initializes the first element to 0. When you do a partial initialization, the rest of the array is automatically initialized with zeros.
Ref. C11 6.7.9:
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.
[I wrote this answer for another question, but it got dup closed. I liked the answer though, so I'm reposting on the original question.]
If struct a a1 = {0}; initializes all the elements (of different types) of a structure to zero, then struct a a2 = {5}; should initialize it to 5.. no?
#include <stdio.h>
typedef struct _a {
int i;
int j;
int k;
}a;
int main(void)
{
a a0;
a a1 = {0};
a a2 = {5};
printf("a0.i = %d \n", a0.i);
printf("a0.j = %d \n", a0.j);
printf("a0.k = %d \n", a0.k);
printf("a1.i = %d \n", a1.i);
printf("a1.j = %d \n", a1.j);
printf("a1.k = %d \n", a1.k);
printf("a2.i = %d \n", a2.i);
printf("a2.j = %d \n", a2.j);
printf("a2.k = %d \n", a2.k);
return 0;
}
The uninitialized struct contains garbage values
a0.i = 134513937
a0.j = 134513456
a0.k = 0
The initialized to 0 struct contains all elements initialized to 0
a1.i = 0
a1.j = 0
a1.k = 0
The initialized to 5 struct contains only the first element initialized to 5 and the rest of the elements initialized to 0.
a2.i = 5
a2.j = 0
a2.k = 0
Would a2.j and a2.k always guaranteed to initialize to 0 during a a2 = {5}; (or) is it an undefined behavior
OTOH, why am I not seeing all the elements of s2 initialized to 5. How is the struct initialization is done during {0} and how is it different when {5} is used?
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.
[EDIT]
Static objects and implicit initialization:
The storage duration of an object determines the lifetime of an object.
There are 3 storage durations:
static, automatic, and allocated
variables declared outside of all blocks and those explicitly declared with the static storage class specifier have static storage duration. Static variables are initialized to zero by default by the compiler.
Consider the following program:
#include<stdio.h>
int main()
{
int i;
static int j;
printf("i = [%d]",i);
printf("j = [%d]",j);
return 0;
}
In the above program, i has automatic storage and since it is not explicitly initialized its value is Undefined.
While j has static storage duration and it is guaranteed to be initialized to 0 by the compiler.
The omitted values will be always initialized to zero, because the standard says so. So you have essentially
struct a a1 = { 0, 0, 0 };
and
struct a a2 = { 5, 0, 0 };
which is of course different.
No. In C, if your initializer list is incomplete, all missing indices will be filled with 0. So this:
int a[3] = {0};
int b[3] = {5};
effectively becomes:
int a[3] = {0, 0, 0};
int b[3] = {5, 0, 0};
This is why it seemingly works with {0} but fails with {5}.
It doesn't work for
struct x {
int *y;
/* ... */
};
struct x xobj = {5};
Take a look at Designated Initializers in GCC documentation.
The behavior is exactly the same in both cases. If there are fewer initializers than there are elements in the aggregate, then the remaining elements are initialized as though they were declared static, meaning they'll be initialized to 0 or NULL.
It's just that in the first case, the explicit initializer has the same value as the implicit initializer.
If you want to initialize all the elements of your aggregate to something other than 0, then you will have to provide an explicit initializer for each of them, i.e.:
a a2 = {5, 5, 5};
I am wondering if:
int a[] = {1, 2};
allocates sizeof(int) * number of constants inside brackets
int a[5] = {1, 2};
assigns constants to array fields from 0 to 1 and then fills with 0
int a[5] = {};
fills with 0
What happens when I do:
int a[] = {};
Thanks.
int a[5] = {};
and
int a[] = {};
are not valid C definitions.
In GNU C (C with gcc extensions), you can use empty {} and it is considered the same as {0}.
Note that int [] is a incomplete type. When initializing an array of an incomplete type with explicit initializers, the type is completed and the number of elements of the array is then the number of elements in the brace enclosed initializer list.
So int a[] = {0}; defines an array of 1 element in C and in GNU C int a[] = {}; does the same.