C99嵌套数组的未定义行为

时间:2020-10-21 09:23:06

标签: c multidimensional-array c99 c-standard-library

在我们的讲座中,我们最近研究了指针相等性(c.6.5.9.6)的c99标准,并将其应用于嵌套数组。那里指出只有在“一个是指针 指向一个数组对象的末尾,另一个是指向另一个数组的开始的指针 恰好紧跟地址中第一个数组对象的数组对象 空间”。

然后,教授解释了这是为什么对尺寸为4 * 5的嵌套数组未定义数组访问a [0] [19]的原因。这是真的?如果是这样,为什么要定义负数索引呢? a [1] [-1]?

1 个答案:

答案 0 :(得分:1)

a[0][19]a[1][-1]都没有C标准定义的行为。

C 2018 6.5.2 / 1 2告诉我们,数组下标是根据指针算术定义的:

后缀表达式后跟方括号[]中的表达式是数组对象元素的下标名称。下标运算符[]的定义是E1[E2](*((E1)+(E2)))相同……

因此a[0][19]*(a[0] + 19)相同(其中省略了一些括号,因为它们是不必要的),而a[1][-1]*(a[1] + -1)相同。

a[0] + 19a[1] + -1中,a[0]a[1]是数组。在这些表达式中,根据C 2018 6.3.2.1,它们将自动转换为指向其第一个元素的指针。因此,这些表达式等效于p + 19q + -1,其中p和{{ 1}}分别是前两个元素q&a[0][0]的地址。

C 2018 6.5.6 8定义了指针算法:

如果指针操作数指向数组对象的元素,并且数组足够大,则结果指向与原始元素偏移的元素,以使结果数组元素和原始数组元素的下标之差等于整数表达式。换句话说,如果表达式a[1][0]指向数组对象的第 i 个元素,则表达式P(相当于(P)+N)和{{ 1}}(其中N+(P)的值为 n )分别指向 i + n -th和 i - n 个元素(如果存在)。此外,如果表达式(P)-N指向数组对象的最后一个元素,则表达式N指向数组对象的最后一个元素,如果表达式P指向数组的最后一个元素数组对象的最后一个元素,表达式(P)+1指向数组对象的最后一个元素。如果指针操作数和结果都指向同一数组对象的元素,或者指向数组对象的最后一个元素,则求值不应产生溢出。否则,行为是不确定的。

因此Q将指向(Q)-1的元素19(如果存在)。但是p + 19是由5个元素组成的数组,因此元素19不存在,因此a[0]的行为未由标准定义。

类似地,a[0]指向p + 19的元素-1,但是元素-1不存在,因此q + -1的行为未由标准定义。

这些数组包含在一个较大的数组中,并且我们知道此较大数组中所有元素的内存布局这一事实无关紧要。 C标准没有根据更大的内存布局来定义行为。它根据要评估指针算术的特定数组指定行为。 C实现可以自由地使此算术像简单地址算术一样工作,并在需要时定义行为,但也可以不这样做。多年来,编译器优化已经变得更加复杂和激进,并且它可以基于C标准关于特定数组算术的规则来转换这些表达式,而不考虑内存布局,并且这可能导致表达式失败(表现不佳)简单的地址算法)。

相关问题