Confusion about array initialization in C
Clash Royale CLAN TAG#URR8PPP
up vote
32
down vote
favorite
In C language, if initialize an array like this:
int a[5] = 1,2;
then all the elements of the array that are not initialized explicitly will be initialized implicitly with zeroes.
But, if I initialize an array like this:
int a[5]=a[2]=1;
printf("%d %d %d %d %dn", a[0], a[1],a[2], a[3], a[4]);
output:
1 0 1 0 0
I don't understand, why does a[0]
print 1
instead of 0
? Is it undefined behaviour?
Note: This question was asked in an interview.
c arrays initialization language-lawyer
 |Â
show 9 more comments
up vote
32
down vote
favorite
In C language, if initialize an array like this:
int a[5] = 1,2;
then all the elements of the array that are not initialized explicitly will be initialized implicitly with zeroes.
But, if I initialize an array like this:
int a[5]=a[2]=1;
printf("%d %d %d %d %dn", a[0], a[1],a[2], a[3], a[4]);
output:
1 0 1 0 0
I don't understand, why does a[0]
print 1
instead of 0
? Is it undefined behaviour?
Note: This question was asked in an interview.
c arrays initialization language-lawyer
11
The expressiona[2]=1
evaluates to1
.
– tkausl
10 hours ago
7
A very deep question. I wonder if the interviewer knows the answer themselves. I don't. Indeed ostensibly the value of the expressiona[2] = 1
is1
, but I'm not sure if you are are allowed to take the result of a designated initialiser expression as the value of the first element. The fact you've added the lawyer tag means I think we need an answer citing the standard.
– Bathsheba
9 hours ago
9
Well if that's their favourite question, you may well have dodged a bullet. Personally I prefer a written programming exercise (with access to a compiler and debugger) to be taken over a few hours rather than "ace" style questions such as the above. I could conject an answer, but I don't think it would have any real factual basis.
– Bathsheba
9 hours ago
1
@Bathsheba I would do the opposite, as the answer here now answers both questions.
– Kami Kaze
8 hours ago
1
@Bathsheba would be the best. Still I would give the credit for the question to OP, as he came up with the topic. But this is not for me to decide just what I feel would be "the right thing".
– Kami Kaze
8 hours ago
 |Â
show 9 more comments
up vote
32
down vote
favorite
up vote
32
down vote
favorite
In C language, if initialize an array like this:
int a[5] = 1,2;
then all the elements of the array that are not initialized explicitly will be initialized implicitly with zeroes.
But, if I initialize an array like this:
int a[5]=a[2]=1;
printf("%d %d %d %d %dn", a[0], a[1],a[2], a[3], a[4]);
output:
1 0 1 0 0
I don't understand, why does a[0]
print 1
instead of 0
? Is it undefined behaviour?
Note: This question was asked in an interview.
c arrays initialization language-lawyer
In C language, if initialize an array like this:
int a[5] = 1,2;
then all the elements of the array that are not initialized explicitly will be initialized implicitly with zeroes.
But, if I initialize an array like this:
int a[5]=a[2]=1;
printf("%d %d %d %d %dn", a[0], a[1],a[2], a[3], a[4]);
output:
1 0 1 0 0
I don't understand, why does a[0]
print 1
instead of 0
? Is it undefined behaviour?
Note: This question was asked in an interview.
c arrays initialization language-lawyer
c arrays initialization language-lawyer
edited 1 hour ago


Jesse de Bruijne
2,28231125
2,28231125
asked 10 hours ago
rsp
17.1k454113
17.1k454113
11
The expressiona[2]=1
evaluates to1
.
– tkausl
10 hours ago
7
A very deep question. I wonder if the interviewer knows the answer themselves. I don't. Indeed ostensibly the value of the expressiona[2] = 1
is1
, but I'm not sure if you are are allowed to take the result of a designated initialiser expression as the value of the first element. The fact you've added the lawyer tag means I think we need an answer citing the standard.
– Bathsheba
9 hours ago
9
Well if that's their favourite question, you may well have dodged a bullet. Personally I prefer a written programming exercise (with access to a compiler and debugger) to be taken over a few hours rather than "ace" style questions such as the above. I could conject an answer, but I don't think it would have any real factual basis.
– Bathsheba
9 hours ago
1
@Bathsheba I would do the opposite, as the answer here now answers both questions.
– Kami Kaze
8 hours ago
1
@Bathsheba would be the best. Still I would give the credit for the question to OP, as he came up with the topic. But this is not for me to decide just what I feel would be "the right thing".
– Kami Kaze
8 hours ago
 |Â
show 9 more comments
11
The expressiona[2]=1
evaluates to1
.
– tkausl
10 hours ago
7
A very deep question. I wonder if the interviewer knows the answer themselves. I don't. Indeed ostensibly the value of the expressiona[2] = 1
is1
, but I'm not sure if you are are allowed to take the result of a designated initialiser expression as the value of the first element. The fact you've added the lawyer tag means I think we need an answer citing the standard.
– Bathsheba
9 hours ago
9
Well if that's their favourite question, you may well have dodged a bullet. Personally I prefer a written programming exercise (with access to a compiler and debugger) to be taken over a few hours rather than "ace" style questions such as the above. I could conject an answer, but I don't think it would have any real factual basis.
– Bathsheba
9 hours ago
1
@Bathsheba I would do the opposite, as the answer here now answers both questions.
– Kami Kaze
8 hours ago
1
@Bathsheba would be the best. Still I would give the credit for the question to OP, as he came up with the topic. But this is not for me to decide just what I feel would be "the right thing".
– Kami Kaze
8 hours ago
11
11
The expression
a[2]=1
evaluates to 1
.– tkausl
10 hours ago
The expression
a[2]=1
evaluates to 1
.– tkausl
10 hours ago
7
7
A very deep question. I wonder if the interviewer knows the answer themselves. I don't. Indeed ostensibly the value of the expression
a[2] = 1
is 1
, but I'm not sure if you are are allowed to take the result of a designated initialiser expression as the value of the first element. The fact you've added the lawyer tag means I think we need an answer citing the standard.– Bathsheba
9 hours ago
A very deep question. I wonder if the interviewer knows the answer themselves. I don't. Indeed ostensibly the value of the expression
a[2] = 1
is 1
, but I'm not sure if you are are allowed to take the result of a designated initialiser expression as the value of the first element. The fact you've added the lawyer tag means I think we need an answer citing the standard.– Bathsheba
9 hours ago
9
9
Well if that's their favourite question, you may well have dodged a bullet. Personally I prefer a written programming exercise (with access to a compiler and debugger) to be taken over a few hours rather than "ace" style questions such as the above. I could conject an answer, but I don't think it would have any real factual basis.
– Bathsheba
9 hours ago
Well if that's their favourite question, you may well have dodged a bullet. Personally I prefer a written programming exercise (with access to a compiler and debugger) to be taken over a few hours rather than "ace" style questions such as the above. I could conject an answer, but I don't think it would have any real factual basis.
– Bathsheba
9 hours ago
1
1
@Bathsheba I would do the opposite, as the answer here now answers both questions.
– Kami Kaze
8 hours ago
@Bathsheba I would do the opposite, as the answer here now answers both questions.
– Kami Kaze
8 hours ago
1
1
@Bathsheba would be the best. Still I would give the credit for the question to OP, as he came up with the topic. But this is not for me to decide just what I feel would be "the right thing".
– Kami Kaze
8 hours ago
@Bathsheba would be the best. Still I would give the credit for the question to OP, as he came up with the topic. But this is not for me to decide just what I feel would be "the right thing".
– Kami Kaze
8 hours ago
 |Â
show 9 more comments
4 Answers
4
active
oldest
votes
up vote
36
down vote
TL;DR: I don't think the behavior of int a[5]=a[2]=1;
is well defined, at least in C99.
The funny part is that the only bit that makes sense to me is the part you're asking about: a[0]
is set to 1
because the assignment operator returns the value that was assigned. It's everything else that's unclear.
If the code had been int a[5] = [2] = 1
, everything would've been easy: That's a designated initializer setting a[2]
to 1
and everything else to 0
. But with a[2] = 1
we have a non-designated initializer containing an assignment expression, and we fall down a rabbit hole.
Here's what I've found so far:
a
must be a local variable.
6.7.8 Initialization
- All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
a[2] = 1
is not a constant expression, soa
must have automatic storage.a
is in scope in its own initialization.
6.2.1 Scopes of identifiers
- Structure, union, and enumeration tags have scope that begins just after the appearance of
the tag in a type specifier that declares the tag. Each enumeration constant has scope that
begins just after the appearance of its defining enumerator in an enumerator list. Any
other identifier has scope that begins just after the completion of its declarator.
The declarator is
a[5]
, so variables are in scope in their own initialization.- Structure, union, and enumeration tags have scope that begins just after the appearance of
a
is alive in its own initialization.
6.2.4 Storage durations of objects
An object whose identifier is declared with no linkage and without the storage-class
specifierstatic
has automatic storage duration.For such an object that does not have a variable length array type, its lifetime extends
from entry into the block with which it is associated until execution of that block ends in
any way. (Entering an enclosed block or calling a function suspends, but does not end,
execution of the current block.) If the block is entered recursively, a new instance of the
object is created each time. The initial value of the object is indeterminate. If an
initialization is specified for the object, it is performed each time the declaration is
reached in the execution of the block; otherwise, the value becomes indeterminate each
time the declaration is reached.
There is a sequence point after
a[2]=1
.
6.8 Statements and blocks
- A full expression is an expression that is not part of another expression or of a declarator.
Each of the following is a full expression: an initializer; the expression in an expression
statement; the controlling expression of a selection statement (if
orswitch
); the
controlling expression of awhile
ordo
statement; each of the (optional) expressions of
afor
statement; the (optional) expression in areturn
statement. The end of a full
expression is a sequence point.
Note that e.g. in
int foo = 1, 2, 3
the1, 2, 3
part is a brace-enclosed list of initializers, each of which has a sequence point after it.- A full expression is an expression that is not part of another expression or of a declarator.
Initialization is performed in initializer list order.
6.7.8 Initialization
- Each brace-enclosed initializer list has an associated current object. When no
designations are present, subobjects of the current object are initialized in order according
to the type of the current object: array elements in increasing subscript order, structure members in declaration order, and the first named member of a union. [...]
Â
- The initialization shall occur in initializer list order, each initializer provided for a
particular subobject overriding any previously listed initializer for the same subobject; all
subobjects that are not initialized explicitly shall be initialized implicitly the same as
objects that have static storage duration.
- Each brace-enclosed initializer list has an associated current object. When no
However, initializer expressions are not necessarily evaluated in order.
6.7.8 Initialization
- The order in which any side effects occur among the initialization list expressions is
unspecified.
- The order in which any side effects occur among the initialization list expressions is
However, that still leaves some questions unanswered:
Are sequence points even relevant? The basic rule is:
6.5 Expressions
- Between the previous and next sequence point an object shall have its stored value
modified at most once by the evaluation of an expression. Furthermore, the prior value
shall be read only to determine the value to be stored.
a[2] = 1
is an expression, but initialization is not.This is slightly contradicted by Annex J:
J.2 Undefined behavior
- Between two sequence points, an object is modified more than once, or is modified
and the prior value is read other than to determine the value to be stored (6.5).
Annex J says any modification counts, not just modifications by expressions. But given that annexes are non-normative, we can probably ignore that.
- Between the previous and next sequence point an object shall have its stored value
How are the subobject initializations sequenced with respect to initializer expressions? Are all initializers evaluated first (in some order), then the subobjects are initialized with the results (in initializer list order)? Or can they be interleaved?
I think int a[5] = a[2] = 1
is executed as follows:
- Storage for
a
is allocated when its containing block is entered. The contents are indeterminate at this point. - The (only) initializer is executed (
a[2] = 1
), followed by a sequence point. This stores1
ina[2]
and returns1
. - That
1
is used to initializea[0]
(the first initializer initializes the first subobject).
But here things get fuzzy because the remaining elements (a[1]
, a[2]
, a[3]
, a[4]
) are supposed to be initialized to 0
, but it's not clear when: Does it happen before a[2] = 1
is evaluated? If so, a[2] = 1
would "win" and overwrite a[2]
, but would that assignment have undefined behavior because there is no sequence point between the zero initialization and the assignment expression? Are sequence points even relevant (see above)? Or does zero initialization happen after all initializers are evaluated? If so, a[2]
should end up being 0
.
Because the C standard does not clearly define what happens here, I believe the behavior is undefined (by omission).
1
Instead of undefined I would argue that it's unspecified, which leave things open for interpretation by the implementations.
– Some programmer dude
7 hours ago
I don't think any of the stuff before your last horizontal rule is relevant to the question; the only issue is when the zero initialization happens (which the standard doesn't seem to say). The same issue would be raised byint a[5] = a[2] = a[3] ;
– M.M
7 hours ago
"we fall into a rabbit hole" LOL! Never heard that for an UB or unspecified stuff.
– BÈþòøћ
6 hours ago
I think 6.7.8.19 can be read in two ways, both of which give "valid" outcomes, but both of which are undesirable readings. 1) We considera[2] = 1
to initializea[2]
(even though it is explicitly not "an initializer" fora[2]
) because it "sets an initial value" (as parenthetically mentioned in 5.1.2), which makes the outcome witha[2] == 1
well-defined (because it was "initialized explicitly" and so mustn't be set to 0). This is undesirable because it sneaks in initialization without an initializer, bypassing all the careful words about how the order of initializers is not specified...
– Jeroen Mostert
3 hours ago
... or 2) we considera[2] = 1
not to initialize by the narrow interpretation of "initialize" where an assignment does not "initialize", but thena[2]
must be set to 0 by 6.7.8.19. This is undesirable because it clashes with the most obvious implementation of initialization (initialize the whole block to 0, then process initializers), puts an undue burden on the compiler, and makes the whole thing useless anyway. I would agree that by the way things are currently worded, the whole thing should probably be considered undefined by virtue of the standard not being explicit enough.
– Jeroen Mostert
3 hours ago
 |Â
show 4 more comments
up vote
14
down vote
I don't understand, why does
a[0]
print1
instead of0
?
Presumably a[2]=1
initializes a[2]
first, and the result of the expression is used to initialize a[0]
.
From N2176 (C17 draft):
6.7.9 Initialization
- The evaluations of the initialization list expressions are indeterminately sequenced with respect to
one another and thus the order in which any side effects occur is unspecified. 154)
So it would seem that output 1 0 0 0 0
would also have been possible.
Conclusion: Don't write initializers that modifies the initialized variable on the fly.
1
That part does not apply: There is only one initializer expression here, so it doesn't need to be sequenced with anything.
– melpomene
8 hours ago
@melpomene There is the...
expression which initializesa[2]
to0
, anda[2]=1
sub-expression which initializesa[2]
to1
.
– user694733
8 hours ago
1
...
is a braced initializer list. It is not an expression.
– melpomene
8 hours ago
@melpomene Ok, you may be right there. But I would still argue there are still 2 competing side-effects so that paragraph stands.
– user694733
8 hours ago
@Gerhardh Yeah, I started having doubts about that too. I removed it. Thanks.
– user694733
7 hours ago
 |Â
show 2 more comments
up vote
1
down vote
My Understanding is a[2]=1
returns value 1 so code becomes
int a[5]=a[2]=1 --> int a[5]=1
int a[5]=1
assign value for a[0]=1
Hence it print 1 for a[0]
For example
char str[10]=‘H’,‘a’,‘i’;
char str[0] = ‘H’;
char str[1] = ‘a’;
char str[2] = ‘i;
add a comment |Â
up vote
1
down vote
I try to give a short and simple answer to the puzzle: int a[5] = a[2] = 1 ;
- First
a[2] = 1
is set. That means the array says:0 0 1 0 0
- But behold, given that you did it in the
1
) and sets that toa[0]
. It is as ifint a[5] = a[2] ;
would remain, where we already gota[2] = 2
. The resulting array is now:1 0 1 0 0
I guess it has to do with declarations being done first (or even the last declaration being done first). Example: A = B = C = 5
, it starts with C = 5
, goes to B = C
, then A = B
.
That raises the question how a[2]
can be declared if the array should not exist yet. Well, it actually does the moment ...
is read, which is logical, given that every value in that bracket must be assigned to an already allocated array anyway. It's special alias/syntax for array initiation.
Small info: Another example:int a[6] = a[3] = 1, a[4] = 2, a[5] = 3 ;
- It goes from left to right, each starting with the internal declaration. It goes in 6 steps:0 0 0 1 0 0
,1 0 0 1 0 0
,1 0 0 1 2 0
,1 2 0 1 2 0
,1 2 0 1 2 3
,1 2 3 1 2 3
.
– Battle
4 hours ago
A = B = C = 5
is not a declaration (or initialization). It's a normal expression that parses asA = (B = (C = 5))
because the=
operator is right associative. That doesn't really help with explaining how initialization works. The array actually starts existing when the block it is defined in is entered, which can be long before the actual definition is executed.
– melpomene
17 mins ago
add a comment |Â
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
36
down vote
TL;DR: I don't think the behavior of int a[5]=a[2]=1;
is well defined, at least in C99.
The funny part is that the only bit that makes sense to me is the part you're asking about: a[0]
is set to 1
because the assignment operator returns the value that was assigned. It's everything else that's unclear.
If the code had been int a[5] = [2] = 1
, everything would've been easy: That's a designated initializer setting a[2]
to 1
and everything else to 0
. But with a[2] = 1
we have a non-designated initializer containing an assignment expression, and we fall down a rabbit hole.
Here's what I've found so far:
a
must be a local variable.
6.7.8 Initialization
- All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
a[2] = 1
is not a constant expression, soa
must have automatic storage.a
is in scope in its own initialization.
6.2.1 Scopes of identifiers
- Structure, union, and enumeration tags have scope that begins just after the appearance of
the tag in a type specifier that declares the tag. Each enumeration constant has scope that
begins just after the appearance of its defining enumerator in an enumerator list. Any
other identifier has scope that begins just after the completion of its declarator.
The declarator is
a[5]
, so variables are in scope in their own initialization.- Structure, union, and enumeration tags have scope that begins just after the appearance of
a
is alive in its own initialization.
6.2.4 Storage durations of objects
An object whose identifier is declared with no linkage and without the storage-class
specifierstatic
has automatic storage duration.For such an object that does not have a variable length array type, its lifetime extends
from entry into the block with which it is associated until execution of that block ends in
any way. (Entering an enclosed block or calling a function suspends, but does not end,
execution of the current block.) If the block is entered recursively, a new instance of the
object is created each time. The initial value of the object is indeterminate. If an
initialization is specified for the object, it is performed each time the declaration is
reached in the execution of the block; otherwise, the value becomes indeterminate each
time the declaration is reached.
There is a sequence point after
a[2]=1
.
6.8 Statements and blocks
- A full expression is an expression that is not part of another expression or of a declarator.
Each of the following is a full expression: an initializer; the expression in an expression
statement; the controlling expression of a selection statement (if
orswitch
); the
controlling expression of awhile
ordo
statement; each of the (optional) expressions of
afor
statement; the (optional) expression in areturn
statement. The end of a full
expression is a sequence point.
Note that e.g. in
int foo = 1, 2, 3
the1, 2, 3
part is a brace-enclosed list of initializers, each of which has a sequence point after it.- A full expression is an expression that is not part of another expression or of a declarator.
Initialization is performed in initializer list order.
6.7.8 Initialization
- Each brace-enclosed initializer list has an associated current object. When no
designations are present, subobjects of the current object are initialized in order according
to the type of the current object: array elements in increasing subscript order, structure members in declaration order, and the first named member of a union. [...]
Â
- The initialization shall occur in initializer list order, each initializer provided for a
particular subobject overriding any previously listed initializer for the same subobject; all
subobjects that are not initialized explicitly shall be initialized implicitly the same as
objects that have static storage duration.
- Each brace-enclosed initializer list has an associated current object. When no
However, initializer expressions are not necessarily evaluated in order.
6.7.8 Initialization
- The order in which any side effects occur among the initialization list expressions is
unspecified.
- The order in which any side effects occur among the initialization list expressions is
However, that still leaves some questions unanswered:
Are sequence points even relevant? The basic rule is:
6.5 Expressions
- Between the previous and next sequence point an object shall have its stored value
modified at most once by the evaluation of an expression. Furthermore, the prior value
shall be read only to determine the value to be stored.
a[2] = 1
is an expression, but initialization is not.This is slightly contradicted by Annex J:
J.2 Undefined behavior
- Between two sequence points, an object is modified more than once, or is modified
and the prior value is read other than to determine the value to be stored (6.5).
Annex J says any modification counts, not just modifications by expressions. But given that annexes are non-normative, we can probably ignore that.
- Between the previous and next sequence point an object shall have its stored value
How are the subobject initializations sequenced with respect to initializer expressions? Are all initializers evaluated first (in some order), then the subobjects are initialized with the results (in initializer list order)? Or can they be interleaved?
I think int a[5] = a[2] = 1
is executed as follows:
- Storage for
a
is allocated when its containing block is entered. The contents are indeterminate at this point. - The (only) initializer is executed (
a[2] = 1
), followed by a sequence point. This stores1
ina[2]
and returns1
. - That
1
is used to initializea[0]
(the first initializer initializes the first subobject).
But here things get fuzzy because the remaining elements (a[1]
, a[2]
, a[3]
, a[4]
) are supposed to be initialized to 0
, but it's not clear when: Does it happen before a[2] = 1
is evaluated? If so, a[2] = 1
would "win" and overwrite a[2]
, but would that assignment have undefined behavior because there is no sequence point between the zero initialization and the assignment expression? Are sequence points even relevant (see above)? Or does zero initialization happen after all initializers are evaluated? If so, a[2]
should end up being 0
.
Because the C standard does not clearly define what happens here, I believe the behavior is undefined (by omission).
1
Instead of undefined I would argue that it's unspecified, which leave things open for interpretation by the implementations.
– Some programmer dude
7 hours ago
I don't think any of the stuff before your last horizontal rule is relevant to the question; the only issue is when the zero initialization happens (which the standard doesn't seem to say). The same issue would be raised byint a[5] = a[2] = a[3] ;
– M.M
7 hours ago
"we fall into a rabbit hole" LOL! Never heard that for an UB or unspecified stuff.
– BÈþòøћ
6 hours ago
I think 6.7.8.19 can be read in two ways, both of which give "valid" outcomes, but both of which are undesirable readings. 1) We considera[2] = 1
to initializea[2]
(even though it is explicitly not "an initializer" fora[2]
) because it "sets an initial value" (as parenthetically mentioned in 5.1.2), which makes the outcome witha[2] == 1
well-defined (because it was "initialized explicitly" and so mustn't be set to 0). This is undesirable because it sneaks in initialization without an initializer, bypassing all the careful words about how the order of initializers is not specified...
– Jeroen Mostert
3 hours ago
... or 2) we considera[2] = 1
not to initialize by the narrow interpretation of "initialize" where an assignment does not "initialize", but thena[2]
must be set to 0 by 6.7.8.19. This is undesirable because it clashes with the most obvious implementation of initialization (initialize the whole block to 0, then process initializers), puts an undue burden on the compiler, and makes the whole thing useless anyway. I would agree that by the way things are currently worded, the whole thing should probably be considered undefined by virtue of the standard not being explicit enough.
– Jeroen Mostert
3 hours ago
 |Â
show 4 more comments
up vote
36
down vote
TL;DR: I don't think the behavior of int a[5]=a[2]=1;
is well defined, at least in C99.
The funny part is that the only bit that makes sense to me is the part you're asking about: a[0]
is set to 1
because the assignment operator returns the value that was assigned. It's everything else that's unclear.
If the code had been int a[5] = [2] = 1
, everything would've been easy: That's a designated initializer setting a[2]
to 1
and everything else to 0
. But with a[2] = 1
we have a non-designated initializer containing an assignment expression, and we fall down a rabbit hole.
Here's what I've found so far:
a
must be a local variable.
6.7.8 Initialization
- All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
a[2] = 1
is not a constant expression, soa
must have automatic storage.a
is in scope in its own initialization.
6.2.1 Scopes of identifiers
- Structure, union, and enumeration tags have scope that begins just after the appearance of
the tag in a type specifier that declares the tag. Each enumeration constant has scope that
begins just after the appearance of its defining enumerator in an enumerator list. Any
other identifier has scope that begins just after the completion of its declarator.
The declarator is
a[5]
, so variables are in scope in their own initialization.- Structure, union, and enumeration tags have scope that begins just after the appearance of
a
is alive in its own initialization.
6.2.4 Storage durations of objects
An object whose identifier is declared with no linkage and without the storage-class
specifierstatic
has automatic storage duration.For such an object that does not have a variable length array type, its lifetime extends
from entry into the block with which it is associated until execution of that block ends in
any way. (Entering an enclosed block or calling a function suspends, but does not end,
execution of the current block.) If the block is entered recursively, a new instance of the
object is created each time. The initial value of the object is indeterminate. If an
initialization is specified for the object, it is performed each time the declaration is
reached in the execution of the block; otherwise, the value becomes indeterminate each
time the declaration is reached.
There is a sequence point after
a[2]=1
.
6.8 Statements and blocks
- A full expression is an expression that is not part of another expression or of a declarator.
Each of the following is a full expression: an initializer; the expression in an expression
statement; the controlling expression of a selection statement (if
orswitch
); the
controlling expression of awhile
ordo
statement; each of the (optional) expressions of
afor
statement; the (optional) expression in areturn
statement. The end of a full
expression is a sequence point.
Note that e.g. in
int foo = 1, 2, 3
the1, 2, 3
part is a brace-enclosed list of initializers, each of which has a sequence point after it.- A full expression is an expression that is not part of another expression or of a declarator.
Initialization is performed in initializer list order.
6.7.8 Initialization
- Each brace-enclosed initializer list has an associated current object. When no
designations are present, subobjects of the current object are initialized in order according
to the type of the current object: array elements in increasing subscript order, structure members in declaration order, and the first named member of a union. [...]
Â
- The initialization shall occur in initializer list order, each initializer provided for a
particular subobject overriding any previously listed initializer for the same subobject; all
subobjects that are not initialized explicitly shall be initialized implicitly the same as
objects that have static storage duration.
- Each brace-enclosed initializer list has an associated current object. When no
However, initializer expressions are not necessarily evaluated in order.
6.7.8 Initialization
- The order in which any side effects occur among the initialization list expressions is
unspecified.
- The order in which any side effects occur among the initialization list expressions is
However, that still leaves some questions unanswered:
Are sequence points even relevant? The basic rule is:
6.5 Expressions
- Between the previous and next sequence point an object shall have its stored value
modified at most once by the evaluation of an expression. Furthermore, the prior value
shall be read only to determine the value to be stored.
a[2] = 1
is an expression, but initialization is not.This is slightly contradicted by Annex J:
J.2 Undefined behavior
- Between two sequence points, an object is modified more than once, or is modified
and the prior value is read other than to determine the value to be stored (6.5).
Annex J says any modification counts, not just modifications by expressions. But given that annexes are non-normative, we can probably ignore that.
- Between the previous and next sequence point an object shall have its stored value
How are the subobject initializations sequenced with respect to initializer expressions? Are all initializers evaluated first (in some order), then the subobjects are initialized with the results (in initializer list order)? Or can they be interleaved?
I think int a[5] = a[2] = 1
is executed as follows:
- Storage for
a
is allocated when its containing block is entered. The contents are indeterminate at this point. - The (only) initializer is executed (
a[2] = 1
), followed by a sequence point. This stores1
ina[2]
and returns1
. - That
1
is used to initializea[0]
(the first initializer initializes the first subobject).
But here things get fuzzy because the remaining elements (a[1]
, a[2]
, a[3]
, a[4]
) are supposed to be initialized to 0
, but it's not clear when: Does it happen before a[2] = 1
is evaluated? If so, a[2] = 1
would "win" and overwrite a[2]
, but would that assignment have undefined behavior because there is no sequence point between the zero initialization and the assignment expression? Are sequence points even relevant (see above)? Or does zero initialization happen after all initializers are evaluated? If so, a[2]
should end up being 0
.
Because the C standard does not clearly define what happens here, I believe the behavior is undefined (by omission).
1
Instead of undefined I would argue that it's unspecified, which leave things open for interpretation by the implementations.
– Some programmer dude
7 hours ago
I don't think any of the stuff before your last horizontal rule is relevant to the question; the only issue is when the zero initialization happens (which the standard doesn't seem to say). The same issue would be raised byint a[5] = a[2] = a[3] ;
– M.M
7 hours ago
"we fall into a rabbit hole" LOL! Never heard that for an UB or unspecified stuff.
– BÈþòøћ
6 hours ago
I think 6.7.8.19 can be read in two ways, both of which give "valid" outcomes, but both of which are undesirable readings. 1) We considera[2] = 1
to initializea[2]
(even though it is explicitly not "an initializer" fora[2]
) because it "sets an initial value" (as parenthetically mentioned in 5.1.2), which makes the outcome witha[2] == 1
well-defined (because it was "initialized explicitly" and so mustn't be set to 0). This is undesirable because it sneaks in initialization without an initializer, bypassing all the careful words about how the order of initializers is not specified...
– Jeroen Mostert
3 hours ago
... or 2) we considera[2] = 1
not to initialize by the narrow interpretation of "initialize" where an assignment does not "initialize", but thena[2]
must be set to 0 by 6.7.8.19. This is undesirable because it clashes with the most obvious implementation of initialization (initialize the whole block to 0, then process initializers), puts an undue burden on the compiler, and makes the whole thing useless anyway. I would agree that by the way things are currently worded, the whole thing should probably be considered undefined by virtue of the standard not being explicit enough.
– Jeroen Mostert
3 hours ago
 |Â
show 4 more comments
up vote
36
down vote
up vote
36
down vote
TL;DR: I don't think the behavior of int a[5]=a[2]=1;
is well defined, at least in C99.
The funny part is that the only bit that makes sense to me is the part you're asking about: a[0]
is set to 1
because the assignment operator returns the value that was assigned. It's everything else that's unclear.
If the code had been int a[5] = [2] = 1
, everything would've been easy: That's a designated initializer setting a[2]
to 1
and everything else to 0
. But with a[2] = 1
we have a non-designated initializer containing an assignment expression, and we fall down a rabbit hole.
Here's what I've found so far:
a
must be a local variable.
6.7.8 Initialization
- All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
a[2] = 1
is not a constant expression, soa
must have automatic storage.a
is in scope in its own initialization.
6.2.1 Scopes of identifiers
- Structure, union, and enumeration tags have scope that begins just after the appearance of
the tag in a type specifier that declares the tag. Each enumeration constant has scope that
begins just after the appearance of its defining enumerator in an enumerator list. Any
other identifier has scope that begins just after the completion of its declarator.
The declarator is
a[5]
, so variables are in scope in their own initialization.- Structure, union, and enumeration tags have scope that begins just after the appearance of
a
is alive in its own initialization.
6.2.4 Storage durations of objects
An object whose identifier is declared with no linkage and without the storage-class
specifierstatic
has automatic storage duration.For such an object that does not have a variable length array type, its lifetime extends
from entry into the block with which it is associated until execution of that block ends in
any way. (Entering an enclosed block or calling a function suspends, but does not end,
execution of the current block.) If the block is entered recursively, a new instance of the
object is created each time. The initial value of the object is indeterminate. If an
initialization is specified for the object, it is performed each time the declaration is
reached in the execution of the block; otherwise, the value becomes indeterminate each
time the declaration is reached.
There is a sequence point after
a[2]=1
.
6.8 Statements and blocks
- A full expression is an expression that is not part of another expression or of a declarator.
Each of the following is a full expression: an initializer; the expression in an expression
statement; the controlling expression of a selection statement (if
orswitch
); the
controlling expression of awhile
ordo
statement; each of the (optional) expressions of
afor
statement; the (optional) expression in areturn
statement. The end of a full
expression is a sequence point.
Note that e.g. in
int foo = 1, 2, 3
the1, 2, 3
part is a brace-enclosed list of initializers, each of which has a sequence point after it.- A full expression is an expression that is not part of another expression or of a declarator.
Initialization is performed in initializer list order.
6.7.8 Initialization
- Each brace-enclosed initializer list has an associated current object. When no
designations are present, subobjects of the current object are initialized in order according
to the type of the current object: array elements in increasing subscript order, structure members in declaration order, and the first named member of a union. [...]
Â
- The initialization shall occur in initializer list order, each initializer provided for a
particular subobject overriding any previously listed initializer for the same subobject; all
subobjects that are not initialized explicitly shall be initialized implicitly the same as
objects that have static storage duration.
- Each brace-enclosed initializer list has an associated current object. When no
However, initializer expressions are not necessarily evaluated in order.
6.7.8 Initialization
- The order in which any side effects occur among the initialization list expressions is
unspecified.
- The order in which any side effects occur among the initialization list expressions is
However, that still leaves some questions unanswered:
Are sequence points even relevant? The basic rule is:
6.5 Expressions
- Between the previous and next sequence point an object shall have its stored value
modified at most once by the evaluation of an expression. Furthermore, the prior value
shall be read only to determine the value to be stored.
a[2] = 1
is an expression, but initialization is not.This is slightly contradicted by Annex J:
J.2 Undefined behavior
- Between two sequence points, an object is modified more than once, or is modified
and the prior value is read other than to determine the value to be stored (6.5).
Annex J says any modification counts, not just modifications by expressions. But given that annexes are non-normative, we can probably ignore that.
- Between the previous and next sequence point an object shall have its stored value
How are the subobject initializations sequenced with respect to initializer expressions? Are all initializers evaluated first (in some order), then the subobjects are initialized with the results (in initializer list order)? Or can they be interleaved?
I think int a[5] = a[2] = 1
is executed as follows:
- Storage for
a
is allocated when its containing block is entered. The contents are indeterminate at this point. - The (only) initializer is executed (
a[2] = 1
), followed by a sequence point. This stores1
ina[2]
and returns1
. - That
1
is used to initializea[0]
(the first initializer initializes the first subobject).
But here things get fuzzy because the remaining elements (a[1]
, a[2]
, a[3]
, a[4]
) are supposed to be initialized to 0
, but it's not clear when: Does it happen before a[2] = 1
is evaluated? If so, a[2] = 1
would "win" and overwrite a[2]
, but would that assignment have undefined behavior because there is no sequence point between the zero initialization and the assignment expression? Are sequence points even relevant (see above)? Or does zero initialization happen after all initializers are evaluated? If so, a[2]
should end up being 0
.
Because the C standard does not clearly define what happens here, I believe the behavior is undefined (by omission).
TL;DR: I don't think the behavior of int a[5]=a[2]=1;
is well defined, at least in C99.
The funny part is that the only bit that makes sense to me is the part you're asking about: a[0]
is set to 1
because the assignment operator returns the value that was assigned. It's everything else that's unclear.
If the code had been int a[5] = [2] = 1
, everything would've been easy: That's a designated initializer setting a[2]
to 1
and everything else to 0
. But with a[2] = 1
we have a non-designated initializer containing an assignment expression, and we fall down a rabbit hole.
Here's what I've found so far:
a
must be a local variable.
6.7.8 Initialization
- All the expressions in an initializer for an object that has static storage duration shall be constant expressions or string literals.
a[2] = 1
is not a constant expression, soa
must have automatic storage.a
is in scope in its own initialization.
6.2.1 Scopes of identifiers
- Structure, union, and enumeration tags have scope that begins just after the appearance of
the tag in a type specifier that declares the tag. Each enumeration constant has scope that
begins just after the appearance of its defining enumerator in an enumerator list. Any
other identifier has scope that begins just after the completion of its declarator.
The declarator is
a[5]
, so variables are in scope in their own initialization.- Structure, union, and enumeration tags have scope that begins just after the appearance of
a
is alive in its own initialization.
6.2.4 Storage durations of objects
An object whose identifier is declared with no linkage and without the storage-class
specifierstatic
has automatic storage duration.For such an object that does not have a variable length array type, its lifetime extends
from entry into the block with which it is associated until execution of that block ends in
any way. (Entering an enclosed block or calling a function suspends, but does not end,
execution of the current block.) If the block is entered recursively, a new instance of the
object is created each time. The initial value of the object is indeterminate. If an
initialization is specified for the object, it is performed each time the declaration is
reached in the execution of the block; otherwise, the value becomes indeterminate each
time the declaration is reached.
There is a sequence point after
a[2]=1
.
6.8 Statements and blocks
- A full expression is an expression that is not part of another expression or of a declarator.
Each of the following is a full expression: an initializer; the expression in an expression
statement; the controlling expression of a selection statement (if
orswitch
); the
controlling expression of awhile
ordo
statement; each of the (optional) expressions of
afor
statement; the (optional) expression in areturn
statement. The end of a full
expression is a sequence point.
Note that e.g. in
int foo = 1, 2, 3
the1, 2, 3
part is a brace-enclosed list of initializers, each of which has a sequence point after it.- A full expression is an expression that is not part of another expression or of a declarator.
Initialization is performed in initializer list order.
6.7.8 Initialization
- Each brace-enclosed initializer list has an associated current object. When no
designations are present, subobjects of the current object are initialized in order according
to the type of the current object: array elements in increasing subscript order, structure members in declaration order, and the first named member of a union. [...]
Â
- The initialization shall occur in initializer list order, each initializer provided for a
particular subobject overriding any previously listed initializer for the same subobject; all
subobjects that are not initialized explicitly shall be initialized implicitly the same as
objects that have static storage duration.
- Each brace-enclosed initializer list has an associated current object. When no
However, initializer expressions are not necessarily evaluated in order.
6.7.8 Initialization
- The order in which any side effects occur among the initialization list expressions is
unspecified.
- The order in which any side effects occur among the initialization list expressions is
However, that still leaves some questions unanswered:
Are sequence points even relevant? The basic rule is:
6.5 Expressions
- Between the previous and next sequence point an object shall have its stored value
modified at most once by the evaluation of an expression. Furthermore, the prior value
shall be read only to determine the value to be stored.
a[2] = 1
is an expression, but initialization is not.This is slightly contradicted by Annex J:
J.2 Undefined behavior
- Between two sequence points, an object is modified more than once, or is modified
and the prior value is read other than to determine the value to be stored (6.5).
Annex J says any modification counts, not just modifications by expressions. But given that annexes are non-normative, we can probably ignore that.
- Between the previous and next sequence point an object shall have its stored value
How are the subobject initializations sequenced with respect to initializer expressions? Are all initializers evaluated first (in some order), then the subobjects are initialized with the results (in initializer list order)? Or can they be interleaved?
I think int a[5] = a[2] = 1
is executed as follows:
- Storage for
a
is allocated when its containing block is entered. The contents are indeterminate at this point. - The (only) initializer is executed (
a[2] = 1
), followed by a sequence point. This stores1
ina[2]
and returns1
. - That
1
is used to initializea[0]
(the first initializer initializes the first subobject).
But here things get fuzzy because the remaining elements (a[1]
, a[2]
, a[3]
, a[4]
) are supposed to be initialized to 0
, but it's not clear when: Does it happen before a[2] = 1
is evaluated? If so, a[2] = 1
would "win" and overwrite a[2]
, but would that assignment have undefined behavior because there is no sequence point between the zero initialization and the assignment expression? Are sequence points even relevant (see above)? Or does zero initialization happen after all initializers are evaluated? If so, a[2]
should end up being 0
.
Because the C standard does not clearly define what happens here, I believe the behavior is undefined (by omission).
edited 8 mins ago
answered 8 hours ago
melpomene
50.4k53682
50.4k53682
1
Instead of undefined I would argue that it's unspecified, which leave things open for interpretation by the implementations.
– Some programmer dude
7 hours ago
I don't think any of the stuff before your last horizontal rule is relevant to the question; the only issue is when the zero initialization happens (which the standard doesn't seem to say). The same issue would be raised byint a[5] = a[2] = a[3] ;
– M.M
7 hours ago
"we fall into a rabbit hole" LOL! Never heard that for an UB or unspecified stuff.
– BÈþòøћ
6 hours ago
I think 6.7.8.19 can be read in two ways, both of which give "valid" outcomes, but both of which are undesirable readings. 1) We considera[2] = 1
to initializea[2]
(even though it is explicitly not "an initializer" fora[2]
) because it "sets an initial value" (as parenthetically mentioned in 5.1.2), which makes the outcome witha[2] == 1
well-defined (because it was "initialized explicitly" and so mustn't be set to 0). This is undesirable because it sneaks in initialization without an initializer, bypassing all the careful words about how the order of initializers is not specified...
– Jeroen Mostert
3 hours ago
... or 2) we considera[2] = 1
not to initialize by the narrow interpretation of "initialize" where an assignment does not "initialize", but thena[2]
must be set to 0 by 6.7.8.19. This is undesirable because it clashes with the most obvious implementation of initialization (initialize the whole block to 0, then process initializers), puts an undue burden on the compiler, and makes the whole thing useless anyway. I would agree that by the way things are currently worded, the whole thing should probably be considered undefined by virtue of the standard not being explicit enough.
– Jeroen Mostert
3 hours ago
 |Â
show 4 more comments
1
Instead of undefined I would argue that it's unspecified, which leave things open for interpretation by the implementations.
– Some programmer dude
7 hours ago
I don't think any of the stuff before your last horizontal rule is relevant to the question; the only issue is when the zero initialization happens (which the standard doesn't seem to say). The same issue would be raised byint a[5] = a[2] = a[3] ;
– M.M
7 hours ago
"we fall into a rabbit hole" LOL! Never heard that for an UB or unspecified stuff.
– BÈþòøћ
6 hours ago
I think 6.7.8.19 can be read in two ways, both of which give "valid" outcomes, but both of which are undesirable readings. 1) We considera[2] = 1
to initializea[2]
(even though it is explicitly not "an initializer" fora[2]
) because it "sets an initial value" (as parenthetically mentioned in 5.1.2), which makes the outcome witha[2] == 1
well-defined (because it was "initialized explicitly" and so mustn't be set to 0). This is undesirable because it sneaks in initialization without an initializer, bypassing all the careful words about how the order of initializers is not specified...
– Jeroen Mostert
3 hours ago
... or 2) we considera[2] = 1
not to initialize by the narrow interpretation of "initialize" where an assignment does not "initialize", but thena[2]
must be set to 0 by 6.7.8.19. This is undesirable because it clashes with the most obvious implementation of initialization (initialize the whole block to 0, then process initializers), puts an undue burden on the compiler, and makes the whole thing useless anyway. I would agree that by the way things are currently worded, the whole thing should probably be considered undefined by virtue of the standard not being explicit enough.
– Jeroen Mostert
3 hours ago
1
1
Instead of undefined I would argue that it's unspecified, which leave things open for interpretation by the implementations.
– Some programmer dude
7 hours ago
Instead of undefined I would argue that it's unspecified, which leave things open for interpretation by the implementations.
– Some programmer dude
7 hours ago
I don't think any of the stuff before your last horizontal rule is relevant to the question; the only issue is when the zero initialization happens (which the standard doesn't seem to say). The same issue would be raised by
int a[5] = a[2] = a[3] ;
– M.M
7 hours ago
I don't think any of the stuff before your last horizontal rule is relevant to the question; the only issue is when the zero initialization happens (which the standard doesn't seem to say). The same issue would be raised by
int a[5] = a[2] = a[3] ;
– M.M
7 hours ago
"we fall into a rabbit hole" LOL! Never heard that for an UB or unspecified stuff.
– BÈþòøћ
6 hours ago
"we fall into a rabbit hole" LOL! Never heard that for an UB or unspecified stuff.
– BÈþòøћ
6 hours ago
I think 6.7.8.19 can be read in two ways, both of which give "valid" outcomes, but both of which are undesirable readings. 1) We consider
a[2] = 1
to initialize a[2]
(even though it is explicitly not "an initializer" for a[2]
) because it "sets an initial value" (as parenthetically mentioned in 5.1.2), which makes the outcome with a[2] == 1
well-defined (because it was "initialized explicitly" and so mustn't be set to 0). This is undesirable because it sneaks in initialization without an initializer, bypassing all the careful words about how the order of initializers is not specified...– Jeroen Mostert
3 hours ago
I think 6.7.8.19 can be read in two ways, both of which give "valid" outcomes, but both of which are undesirable readings. 1) We consider
a[2] = 1
to initialize a[2]
(even though it is explicitly not "an initializer" for a[2]
) because it "sets an initial value" (as parenthetically mentioned in 5.1.2), which makes the outcome with a[2] == 1
well-defined (because it was "initialized explicitly" and so mustn't be set to 0). This is undesirable because it sneaks in initialization without an initializer, bypassing all the careful words about how the order of initializers is not specified...– Jeroen Mostert
3 hours ago
... or 2) we consider
a[2] = 1
not to initialize by the narrow interpretation of "initialize" where an assignment does not "initialize", but then a[2]
must be set to 0 by 6.7.8.19. This is undesirable because it clashes with the most obvious implementation of initialization (initialize the whole block to 0, then process initializers), puts an undue burden on the compiler, and makes the whole thing useless anyway. I would agree that by the way things are currently worded, the whole thing should probably be considered undefined by virtue of the standard not being explicit enough.– Jeroen Mostert
3 hours ago
... or 2) we consider
a[2] = 1
not to initialize by the narrow interpretation of "initialize" where an assignment does not "initialize", but then a[2]
must be set to 0 by 6.7.8.19. This is undesirable because it clashes with the most obvious implementation of initialization (initialize the whole block to 0, then process initializers), puts an undue burden on the compiler, and makes the whole thing useless anyway. I would agree that by the way things are currently worded, the whole thing should probably be considered undefined by virtue of the standard not being explicit enough.– Jeroen Mostert
3 hours ago
 |Â
show 4 more comments
up vote
14
down vote
I don't understand, why does
a[0]
print1
instead of0
?
Presumably a[2]=1
initializes a[2]
first, and the result of the expression is used to initialize a[0]
.
From N2176 (C17 draft):
6.7.9 Initialization
- The evaluations of the initialization list expressions are indeterminately sequenced with respect to
one another and thus the order in which any side effects occur is unspecified. 154)
So it would seem that output 1 0 0 0 0
would also have been possible.
Conclusion: Don't write initializers that modifies the initialized variable on the fly.
1
That part does not apply: There is only one initializer expression here, so it doesn't need to be sequenced with anything.
– melpomene
8 hours ago
@melpomene There is the...
expression which initializesa[2]
to0
, anda[2]=1
sub-expression which initializesa[2]
to1
.
– user694733
8 hours ago
1
...
is a braced initializer list. It is not an expression.
– melpomene
8 hours ago
@melpomene Ok, you may be right there. But I would still argue there are still 2 competing side-effects so that paragraph stands.
– user694733
8 hours ago
@Gerhardh Yeah, I started having doubts about that too. I removed it. Thanks.
– user694733
7 hours ago
 |Â
show 2 more comments
up vote
14
down vote
I don't understand, why does
a[0]
print1
instead of0
?
Presumably a[2]=1
initializes a[2]
first, and the result of the expression is used to initialize a[0]
.
From N2176 (C17 draft):
6.7.9 Initialization
- The evaluations of the initialization list expressions are indeterminately sequenced with respect to
one another and thus the order in which any side effects occur is unspecified. 154)
So it would seem that output 1 0 0 0 0
would also have been possible.
Conclusion: Don't write initializers that modifies the initialized variable on the fly.
1
That part does not apply: There is only one initializer expression here, so it doesn't need to be sequenced with anything.
– melpomene
8 hours ago
@melpomene There is the...
expression which initializesa[2]
to0
, anda[2]=1
sub-expression which initializesa[2]
to1
.
– user694733
8 hours ago
1
...
is a braced initializer list. It is not an expression.
– melpomene
8 hours ago
@melpomene Ok, you may be right there. But I would still argue there are still 2 competing side-effects so that paragraph stands.
– user694733
8 hours ago
@Gerhardh Yeah, I started having doubts about that too. I removed it. Thanks.
– user694733
7 hours ago
 |Â
show 2 more comments
up vote
14
down vote
up vote
14
down vote
I don't understand, why does
a[0]
print1
instead of0
?
Presumably a[2]=1
initializes a[2]
first, and the result of the expression is used to initialize a[0]
.
From N2176 (C17 draft):
6.7.9 Initialization
- The evaluations of the initialization list expressions are indeterminately sequenced with respect to
one another and thus the order in which any side effects occur is unspecified. 154)
So it would seem that output 1 0 0 0 0
would also have been possible.
Conclusion: Don't write initializers that modifies the initialized variable on the fly.
I don't understand, why does
a[0]
print1
instead of0
?
Presumably a[2]=1
initializes a[2]
first, and the result of the expression is used to initialize a[0]
.
From N2176 (C17 draft):
6.7.9 Initialization
- The evaluations of the initialization list expressions are indeterminately sequenced with respect to
one another and thus the order in which any side effects occur is unspecified. 154)
So it would seem that output 1 0 0 0 0
would also have been possible.
Conclusion: Don't write initializers that modifies the initialized variable on the fly.
edited 7 hours ago
answered 8 hours ago
user694733
10.3k12749
10.3k12749
1
That part does not apply: There is only one initializer expression here, so it doesn't need to be sequenced with anything.
– melpomene
8 hours ago
@melpomene There is the...
expression which initializesa[2]
to0
, anda[2]=1
sub-expression which initializesa[2]
to1
.
– user694733
8 hours ago
1
...
is a braced initializer list. It is not an expression.
– melpomene
8 hours ago
@melpomene Ok, you may be right there. But I would still argue there are still 2 competing side-effects so that paragraph stands.
– user694733
8 hours ago
@Gerhardh Yeah, I started having doubts about that too. I removed it. Thanks.
– user694733
7 hours ago
 |Â
show 2 more comments
1
That part does not apply: There is only one initializer expression here, so it doesn't need to be sequenced with anything.
– melpomene
8 hours ago
@melpomene There is the...
expression which initializesa[2]
to0
, anda[2]=1
sub-expression which initializesa[2]
to1
.
– user694733
8 hours ago
1
...
is a braced initializer list. It is not an expression.
– melpomene
8 hours ago
@melpomene Ok, you may be right there. But I would still argue there are still 2 competing side-effects so that paragraph stands.
– user694733
8 hours ago
@Gerhardh Yeah, I started having doubts about that too. I removed it. Thanks.
– user694733
7 hours ago
1
1
That part does not apply: There is only one initializer expression here, so it doesn't need to be sequenced with anything.
– melpomene
8 hours ago
That part does not apply: There is only one initializer expression here, so it doesn't need to be sequenced with anything.
– melpomene
8 hours ago
@melpomene There is the
...
expression which initializes a[2]
to 0
, and a[2]=1
sub-expression which initializes a[2]
to 1
.– user694733
8 hours ago
@melpomene There is the
...
expression which initializes a[2]
to 0
, and a[2]=1
sub-expression which initializes a[2]
to 1
.– user694733
8 hours ago
1
1
...
is a braced initializer list. It is not an expression.– melpomene
8 hours ago
...
is a braced initializer list. It is not an expression.– melpomene
8 hours ago
@melpomene Ok, you may be right there. But I would still argue there are still 2 competing side-effects so that paragraph stands.
– user694733
8 hours ago
@melpomene Ok, you may be right there. But I would still argue there are still 2 competing side-effects so that paragraph stands.
– user694733
8 hours ago
@Gerhardh Yeah, I started having doubts about that too. I removed it. Thanks.
– user694733
7 hours ago
@Gerhardh Yeah, I started having doubts about that too. I removed it. Thanks.
– user694733
7 hours ago
 |Â
show 2 more comments
up vote
1
down vote
My Understanding is a[2]=1
returns value 1 so code becomes
int a[5]=a[2]=1 --> int a[5]=1
int a[5]=1
assign value for a[0]=1
Hence it print 1 for a[0]
For example
char str[10]=‘H’,‘a’,‘i’;
char str[0] = ‘H’;
char str[1] = ‘a’;
char str[2] = ‘i;
add a comment |Â
up vote
1
down vote
My Understanding is a[2]=1
returns value 1 so code becomes
int a[5]=a[2]=1 --> int a[5]=1
int a[5]=1
assign value for a[0]=1
Hence it print 1 for a[0]
For example
char str[10]=‘H’,‘a’,‘i’;
char str[0] = ‘H’;
char str[1] = ‘a’;
char str[2] = ‘i;
add a comment |Â
up vote
1
down vote
up vote
1
down vote
My Understanding is a[2]=1
returns value 1 so code becomes
int a[5]=a[2]=1 --> int a[5]=1
int a[5]=1
assign value for a[0]=1
Hence it print 1 for a[0]
For example
char str[10]=‘H’,‘a’,‘i’;
char str[0] = ‘H’;
char str[1] = ‘a’;
char str[2] = ‘i;
My Understanding is a[2]=1
returns value 1 so code becomes
int a[5]=a[2]=1 --> int a[5]=1
int a[5]=1
assign value for a[0]=1
Hence it print 1 for a[0]
For example
char str[10]=‘H’,‘a’,‘i’;
char str[0] = ‘H’;
char str[1] = ‘a’;
char str[2] = ‘i;
answered 6 hours ago


Karthika Kavi
425
425
add a comment |Â
add a comment |Â
up vote
1
down vote
I try to give a short and simple answer to the puzzle: int a[5] = a[2] = 1 ;
- First
a[2] = 1
is set. That means the array says:0 0 1 0 0
- But behold, given that you did it in the
1
) and sets that toa[0]
. It is as ifint a[5] = a[2] ;
would remain, where we already gota[2] = 2
. The resulting array is now:1 0 1 0 0
I guess it has to do with declarations being done first (or even the last declaration being done first). Example: A = B = C = 5
, it starts with C = 5
, goes to B = C
, then A = B
.
That raises the question how a[2]
can be declared if the array should not exist yet. Well, it actually does the moment ...
is read, which is logical, given that every value in that bracket must be assigned to an already allocated array anyway. It's special alias/syntax for array initiation.
Small info: Another example:int a[6] = a[3] = 1, a[4] = 2, a[5] = 3 ;
- It goes from left to right, each starting with the internal declaration. It goes in 6 steps:0 0 0 1 0 0
,1 0 0 1 0 0
,1 0 0 1 2 0
,1 2 0 1 2 0
,1 2 0 1 2 3
,1 2 3 1 2 3
.
– Battle
4 hours ago
A = B = C = 5
is not a declaration (or initialization). It's a normal expression that parses asA = (B = (C = 5))
because the=
operator is right associative. That doesn't really help with explaining how initialization works. The array actually starts existing when the block it is defined in is entered, which can be long before the actual definition is executed.
– melpomene
17 mins ago
add a comment |Â
up vote
1
down vote
I try to give a short and simple answer to the puzzle: int a[5] = a[2] = 1 ;
- First
a[2] = 1
is set. That means the array says:0 0 1 0 0
- But behold, given that you did it in the
1
) and sets that toa[0]
. It is as ifint a[5] = a[2] ;
would remain, where we already gota[2] = 2
. The resulting array is now:1 0 1 0 0
I guess it has to do with declarations being done first (or even the last declaration being done first). Example: A = B = C = 5
, it starts with C = 5
, goes to B = C
, then A = B
.
That raises the question how a[2]
can be declared if the array should not exist yet. Well, it actually does the moment ...
is read, which is logical, given that every value in that bracket must be assigned to an already allocated array anyway. It's special alias/syntax for array initiation.
Small info: Another example:int a[6] = a[3] = 1, a[4] = 2, a[5] = 3 ;
- It goes from left to right, each starting with the internal declaration. It goes in 6 steps:0 0 0 1 0 0
,1 0 0 1 0 0
,1 0 0 1 2 0
,1 2 0 1 2 0
,1 2 0 1 2 3
,1 2 3 1 2 3
.
– Battle
4 hours ago
A = B = C = 5
is not a declaration (or initialization). It's a normal expression that parses asA = (B = (C = 5))
because the=
operator is right associative. That doesn't really help with explaining how initialization works. The array actually starts existing when the block it is defined in is entered, which can be long before the actual definition is executed.
– melpomene
17 mins ago
add a comment |Â
up vote
1
down vote
up vote
1
down vote
I try to give a short and simple answer to the puzzle: int a[5] = a[2] = 1 ;
- First
a[2] = 1
is set. That means the array says:0 0 1 0 0
- But behold, given that you did it in the
1
) and sets that toa[0]
. It is as ifint a[5] = a[2] ;
would remain, where we already gota[2] = 2
. The resulting array is now:1 0 1 0 0
I guess it has to do with declarations being done first (or even the last declaration being done first). Example: A = B = C = 5
, it starts with C = 5
, goes to B = C
, then A = B
.
That raises the question how a[2]
can be declared if the array should not exist yet. Well, it actually does the moment ...
is read, which is logical, given that every value in that bracket must be assigned to an already allocated array anyway. It's special alias/syntax for array initiation.
I try to give a short and simple answer to the puzzle: int a[5] = a[2] = 1 ;
- First
a[2] = 1
is set. That means the array says:0 0 1 0 0
- But behold, given that you did it in the
1
) and sets that toa[0]
. It is as ifint a[5] = a[2] ;
would remain, where we already gota[2] = 2
. The resulting array is now:1 0 1 0 0
I guess it has to do with declarations being done first (or even the last declaration being done first). Example: A = B = C = 5
, it starts with C = 5
, goes to B = C
, then A = B
.
That raises the question how a[2]
can be declared if the array should not exist yet. Well, it actually does the moment ...
is read, which is logical, given that every value in that bracket must be assigned to an already allocated array anyway. It's special alias/syntax for array initiation.
answered 4 hours ago
Battle
27817
27817
Small info: Another example:int a[6] = a[3] = 1, a[4] = 2, a[5] = 3 ;
- It goes from left to right, each starting with the internal declaration. It goes in 6 steps:0 0 0 1 0 0
,1 0 0 1 0 0
,1 0 0 1 2 0
,1 2 0 1 2 0
,1 2 0 1 2 3
,1 2 3 1 2 3
.
– Battle
4 hours ago
A = B = C = 5
is not a declaration (or initialization). It's a normal expression that parses asA = (B = (C = 5))
because the=
operator is right associative. That doesn't really help with explaining how initialization works. The array actually starts existing when the block it is defined in is entered, which can be long before the actual definition is executed.
– melpomene
17 mins ago
add a comment |Â
Small info: Another example:int a[6] = a[3] = 1, a[4] = 2, a[5] = 3 ;
- It goes from left to right, each starting with the internal declaration. It goes in 6 steps:0 0 0 1 0 0
,1 0 0 1 0 0
,1 0 0 1 2 0
,1 2 0 1 2 0
,1 2 0 1 2 3
,1 2 3 1 2 3
.
– Battle
4 hours ago
A = B = C = 5
is not a declaration (or initialization). It's a normal expression that parses asA = (B = (C = 5))
because the=
operator is right associative. That doesn't really help with explaining how initialization works. The array actually starts existing when the block it is defined in is entered, which can be long before the actual definition is executed.
– melpomene
17 mins ago
Small info: Another example:
int a[6] = a[3] = 1, a[4] = 2, a[5] = 3 ;
- It goes from left to right, each starting with the internal declaration. It goes in 6 steps: 0 0 0 1 0 0
, 1 0 0 1 0 0
, 1 0 0 1 2 0
, 1 2 0 1 2 0
, 1 2 0 1 2 3
, 1 2 3 1 2 3
.– Battle
4 hours ago
Small info: Another example:
int a[6] = a[3] = 1, a[4] = 2, a[5] = 3 ;
- It goes from left to right, each starting with the internal declaration. It goes in 6 steps: 0 0 0 1 0 0
, 1 0 0 1 0 0
, 1 0 0 1 2 0
, 1 2 0 1 2 0
, 1 2 0 1 2 3
, 1 2 3 1 2 3
.– Battle
4 hours ago
A = B = C = 5
is not a declaration (or initialization). It's a normal expression that parses as A = (B = (C = 5))
because the =
operator is right associative. That doesn't really help with explaining how initialization works. The array actually starts existing when the block it is defined in is entered, which can be long before the actual definition is executed.– melpomene
17 mins ago
A = B = C = 5
is not a declaration (or initialization). It's a normal expression that parses as A = (B = (C = 5))
because the =
operator is right associative. That doesn't really help with explaining how initialization works. The array actually starts existing when the block it is defined in is entered, which can be long before the actual definition is executed.– melpomene
17 mins ago
add a comment |Â
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f52307474%2fconfusion-about-array-initialization-in-c%23new-answer', 'question_page');
);
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Sign up or log in
StackExchange.ready(function ()
StackExchange.helpers.onClickDraftSave('#login-link');
);
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
11
The expression
a[2]=1
evaluates to1
.– tkausl
10 hours ago
7
A very deep question. I wonder if the interviewer knows the answer themselves. I don't. Indeed ostensibly the value of the expression
a[2] = 1
is1
, but I'm not sure if you are are allowed to take the result of a designated initialiser expression as the value of the first element. The fact you've added the lawyer tag means I think we need an answer citing the standard.– Bathsheba
9 hours ago
9
Well if that's their favourite question, you may well have dodged a bullet. Personally I prefer a written programming exercise (with access to a compiler and debugger) to be taken over a few hours rather than "ace" style questions such as the above. I could conject an answer, but I don't think it would have any real factual basis.
– Bathsheba
9 hours ago
1
@Bathsheba I would do the opposite, as the answer here now answers both questions.
– Kami Kaze
8 hours ago
1
@Bathsheba would be the best. Still I would give the credit for the question to OP, as he came up with the topic. But this is not for me to decide just what I feel would be "the right thing".
– Kami Kaze
8 hours ago