我正在C中尝试一些与数组相关的东西。
我做了以下事情:
char a2[4] = {'g','e','e','k','s'};
printf("a2:%s,%u\n",a2,sizeof(a2));
printf("a2[4]:%d,%c\n",a2[4],a2[4]);
在此code中,它打印:
a2:geek,4
a2[4]:0,
在此code中,它打印:
a2:geek�,4
a2[4]:-1,�
两个代码都在同一在线编译器上运行。那么为什么输出不同。是因为标准将这种情况定义为未定义的行为。如果是,您能指出我标准的确切部分吗?
答案 0 :(得分:2)
是的,这是未定义的行为。我没有对该标准的引用,但是%s
格式用于打印以null终止的字符串,并且您在a2
上没有null终止符。而且,当您访问a2[4]
时,您将访问数组边界之外,这是导致行为未定义的另一个原因。
最后,数组初始化程序还会导致未定义的行为,请参见Is it ok to have excess elements in array initializer?
答案 1 :(得分:0)
过多的初始化程序的存在违反了C 2018 6.7.9 2中的约束:
初始化器不得尝试为未包含在正在初始化的实体中的对象提供值。
'k'
和's'
将为a2[4]
和a2[5]
提供初始值。由于a2[4]
或a2[5]
不存在,因此它们不包含在a2
中,因此违反了约束。
也就是说,编译器通常会发出警告,然后忽略多余的初始化程序,然后继续。这是您显示的代码中最少的问题,并且对您看到的输出没有影响。
在定义a2
之后,使用%s
打印它。 %s
需要一个指向以空字符终止的字符序列中第一个字符的指针。但是,a2
中没有空字符。所得行为未由C标准定义。通常,发生的情况是程序将继续从阵列之外的内存中打印字符。当然,这不能保证,在现代高度优化的环境中尤其不可靠。
假设printf
确实继续在数组之外打印字符,看来,在一个系统上,数组之外恰好有一个空字符,因此printf
在四个字符之后停止。稍后当您将a2[4]
(也是C标准未定义的行为)打印为整数(%d
)和字符(%c
)时,我们确实发现那里确实有一个空字符。
在另一个系统上,a2[4]
处的内存中有一个-1值,显示为“ ...”。此后,可能有一定数量的非打印字符(可能为零)和一个空字符。
此外,您还使用sizeof(a2)
说明符printf
打印%u
。这是不正确的,并且可能具有未定义的行为。 sizeof
的结果的正确说明符是%zu
。