用较大的数组初始化字符数组时的行为

时间:2018-12-07 17:11:17

标签: c arrays

我正在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,� 

两个代码都在同一在线编译器上运行。那么为什么输出不同。是因为标准将这种情况定义为未定义的行为。如果是,您能指出我标准的确切部分吗?

2 个答案:

答案 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