gpt4 book ai didi

c - 构成末尾之后第一个元素的地址是合法还是越界?

转载 作者:行者123 更新时间:2023-11-30 18:44:10 25 4
gpt4 key购买 nike

在另一个问题中我看到&studmark[STUDNO][0]哪里STUDNO是数组的大小。

我现在想知道该代码是否已经是未定义的行为。 studmark[STUDNO]是最后一位,虽然它可能被创建,但不能被访问。正在使用 [0] 对其进行索引那么形成的地址有效吗?或者必须简单地使用studmark[STUDNO]然后它会降级为一个指针?

无论哪种方式,请引用标准。

更新:示例代码和输出

#include <stdio.h>

#define STUDNO 16

int studmark[STUDNO][2];

int main() {
printf("&studmark = %p\n", studmark);
printf("&studmark[1][0] = %p\n", &studmark[1][0]);
printf("&studmark[STUDNO-1][0] = %p\n", &studmark[STUDNO-1][0]);
printf("&studmark[STUDNO][0] = %p\n", &studmark[STUDNO][0]);
return 0;
}

编译没有给出警告和输出:

./foo 
&studmark = 0x601060
&studmark[1][0] = 0x601068
&studmark[STUDNO-1][0] = 0x6010d8
&studmark[STUDNO][0] = 0x6010e0

最佳答案

鉴于 studmark 的定义如下所示:

int studmark[STUDNO][2];

然后表达式&studmark[STUDNO][0] 调用undefined behavior .

为了使指针取消引用更加明显,首先我们将从数组索引表示法切换为指针表示法。 C11 标准第 6.5.2.1p2 节规定:

The definition of the subscript operator [] is that E1[E2] is identical to (*((E1)+(E2)))

所以上面的表达式就变成了:

&*(studmark[STUDNO] + 0)

变成:

&*(*(studmark + STUDNO) + 0)

此表达式以 &* 运算符开头。当 & 位于 * 之前时,它们会相互抵消。第 6.5.3.2p3 节对此进行了详细说明:

The unary & operator yields the address of its operand. If the operand has type "type", the result has type "pointer to type". If the operand is the result of a unary * operator, neither that operator nor the & operator is evaluated and the result is as if both were omitted, except that the constraints on the operators still apply and the result is not an lvalue.

所以这可以简化为:

*(studmark + STUDNO) + 0

现在我们看看添加的内容。这是有效的,因为根据第 6.5.6p8 节,创建指向超出数组末尾的一个元素的指针是合法的:

When an expression that has integer type is added to or subtracted from a pointer, the result has the type of the pointer operand. If the pointer operand points to an element of an array object, and the array is large enough, the result points to an element offset from the original element such that the difference of the subscripts of the resulting and original array elements equals the integer expression. In other words, if the expression P points to the ith element of an array object, the expressions (P)+N (equivalently,
N+(P)
) and (P)-N (where N has the value n) point to, respectively, the i+nth and i−nth elements of the array object, provided they exist. Moreover, if the expression P points to the last element of an array object, the expression (P)+1 points one past the last element of the array object, and if the expression Q points one past the last element of an array object, the expression (Q)-1 points to the last element of the array object. If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined. If the result points one past the last element of the array object, it shall not be used as the operand of a unary * operator that is evaluated.

这意味着studmark + STUDNO是一个有效的指针,但不能取消引用。这就是问题所在。*(studmark + STUDNO) 会调用未定义的行为,因为它取消引用超出数组末尾的一个元素。

因此 &studmark[STUDNO][0] 是未定义的行为。

相反,这是有效的:

&studmark[STUDNO]

因为它等于:

&*(studmark + STUDNO)

随后:

studmark + STUDNO

因为它创建一个指向数组末尾之后的一个元素的指针,但不会取消引用它。

关于c - 构成末尾之后第一个元素的地址是合法还是越界?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58858493/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com