在C语言中,如果初始化这样的数组:
int a[5] = {1,2}; 那么所有未显式初始化的数组元素将被隐式初始化为零。
但是,如果我这样初始化一个数组:
int a[5]={a[2]=1};
printf("%d %d %d %d %d\n", a[0], a[1],a[2], a[3], a[4]); 输出:
1 0 1 0 0 我不明白,为什么要a[0]打印1而不是0?它是不确定的行为吗?
注意:这个问题是在采访中提出的。 问题来源于stack overflow
版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。
TL; DR:我认为int a[5]={a[2]=1};,至少在C99中,行为没有明确定义。
有趣的是,对我来说唯一有意义的部分就是您要询问的部分:a[0]设置1为该值,因为赋值运算符返回已赋值。尚不清楚其他所有内容。
如果有代码int a[5] = { [2] = 1 },一切将变得很容易:这是一个指定的初始值设定a[2],1其他都是0。但是{ a[2] = 1 }有了一个包含赋值表达式的非指定初始化程序,我们就陷入了困境。
到目前为止,这是我发现的内容:
a 必须是局部变量。
6.7.8初始化
具有静态存储持续时间的对象的初始化程序中的所有表达式应为常量表达式或字符串文字。 a[2] = 1不是常量表达式,因此a必须具有自动存储功能。
a 在自己的初始化范围内。
6.2.1标识符范围
结构,联合和枚举标签的作用域始于在声明标签的类型说明符中出现标签之后。每个枚举常量的作用域都在其定义的枚举器出现在枚举器列表之后立即开始。任何其他标识符的作用域都在其声明符完成之后立即开始。 声明符为a[5],因此变量在其自身的初始化范围内。
a 在自己的初始化中还活着。
6.2.4对象的存储期限
声明其标识符没有链接且没有存储类说明符的对象static具有自动存储期限。
对于不具有可变长度数组类型的对象,其生存期从进入与之关联的块的时间开始,直到该块的执行以任何方式结束。(进入封闭的块或调用函数会挂起,但不会结束当前块的执行。)如果递归地输入该块,则每次都会创建该对象的新实例。对象的初始值不确定。如果为该对象指定了初始化,则每次在块执行中到达声明时都将执行该初始化。否则,每次到达声明时,该值将变得不确定。
之后有一个序列点a[2]=1。
6.8语句和块
甲充分表达是不是另一个表达式或一声明符的一部分的表达。以下每个都是完整的表达式:初始值设定项;表达式语句中的表达式;选择语句(if或switch)的控制表达式;whileor do语句的控制表达式;for语句的每个(可选)表达式;return语句中的(可选)表达式。完整表达式的结尾是一个序列点。 请注意,例如,在int foo[] = { 1, 2, 3 }该{ 1, 2, 3 }部分中有一个用括号括起来的初始化器列表,每个初始化器后都有一个序列点。
初始化以初始化列表的顺序执行。
6.7.8初始化
每个用大括号括起来的初始化器列表都有一个关联的当前对象。如果没有指定,则根据当前对象的类型按顺序初始化当前对象的子对象:下标顺序递增的数组元素,声明顺序的结构成员以及并集的第一个命名成员。[...]
初始化应以初始化程序列表的顺序进行,为特定子对象提供的每个初始化程序都将覆盖先前为同一子对象列出的所有初始化程序。所有未明确初始化的子对象都应与具有静态存储持续时间的对象隐式初始化。 但是,初始化表达式不一定按顺序求值。
6.7.8初始化
在初始化列表表达式中,任何副作用发生的顺序是不确定的。 但是,这仍然有一些问题无法解答:
序列点是否相关?基本规则是:
6.5表达式
在上一个序列点与下一个序列点之间,对象的存储值最多只能通过对表达式的求值来修改。此外,在先值仅应被读取以确定要存储的值。 a[2] = 1 是一个表达式,但初始化不是。
这与附件J有点矛盾:
J.2未定义行为
在两个序列点之间,一个对象被修改了一次以上,或者被修改并且除了确定要存储的值以外,还读取了先前的值(6.5)。 附件J列出了所有修饰计数,而不仅仅是表达式修饰。但是,鉴于附件是非规范性的,我们可能会忽略这一点。
子对象初始化如何相对于初始化器表达式排序?是否首先评估所有初始化程序(以某种顺序),然后用结果初始化子对象(以初始化程序列表的顺序)?还是可以将它们交错?
我认为int a[5] = { a[2] = 1 }执行如下:
a当输入for的存储块时,将为其分配存储空间。此时的内容不确定。 (仅)初始化程序将执行(a[2] = 1),后跟序列点。此店1在a[2]和回报1。 那1用于初始化a[0](第一个初始化器初始化第一个子对象)。 但在这里事情变得模糊,因为剩余的元素(a[1],a[2],a[3],a[4]),都应该被初始化0,但是当它目前还不清楚:是否之前发生的a[2] = 1评价?如果是这样,a[2] = 1“ win”和overwrite a[2]会被覆盖,但是该赋值是否具有未定义的行为,因为在零初始化和赋值表达式之间没有序列点?序列点是否相关(请参见上文)?还是在评估完所有初始化程序后发生零初始化?如果是这样,a[2]最终应该是0。
因为C标准没有明确定义此处发生的情况,所以我认为行为是不确定的(忽略)。