可能是重复的问题:
通过下标取一个超出数组边界的元素的地址:按照C++标准是否合法?
int array[10];
int* a = array + 10; // well-defined
int* b = &array[10]; // not sure...
最后一行是有效的还是无效的?
可能是重复的问题:
通过下标取一个超出数组边界的元素的地址:按照C++标准是否合法?
int array[10];
int* a = array + 10; // well-defined
int* b = &array[10]; // not sure...
最后一行是有效的还是无效的?
是的,你可以访问数组末尾之外的地址,但是你不能对其进行取值操作。对于一个包含10个元素的数组,array+10
是有效的。委员会和其他人多次争论过 &array[10]
是否真的会导致未定义的行为(如果确实会,是否应该)。结果是至少根据当前的标准(包括 C 和 C++),这将正式导致未定义的行为。但是,如果有一个编译器实际上无法处理它,那么在任何争论中,没有人能够找到或引用这个编译器。
编辑:我的记忆好像半对半错——这是(部分)提交给委员会的一个官方缺陷报告,至少一些委员会成员(例如 Tom Plum)认为已经更改措辞,使得它不会导致未定义的行为。然而,这个 DR 是2000年的,状态仍然是“起草”状态,因此它是否真的被修复,或者是否可能被修复,还有待商榷(我没有查看 N3090/3092 来确定)。
然而,在 C99 中,显然不会导致未定义的行为。
array[10]
等同于*(array + 10)
,这似乎会导致对数组末尾刚过边界的元素进行未定义的解引用。然而,表达式&array[10]
等同于&*(array + 10)
,C99标准明确规定(6.5.3.2地址和间接运算符):
因此,一元操作符&返回它的操作数的地址。如果操作数的类型是“type”,则结果的类型是“type”的指针。如果操作数是一元
*
操作符的结果,则既不评估该运算符也不评估&
操作符,并且结果就好像两者都省略了一样,但是运算符的约束仍然适用,并且结果不是lvalue。类似地,如果操作数是[]
操作符的结果,则既不评估&
操作符也不评估由[]
隐含的一元*
,并且结果就好像删除了&
操作符并将[]
操作符更改为+操作符。
&array[10]
没有任何未定义的行为-没有发生解引用操作。array[10]
相当于 *(array + 10)
。换句话说,你已经解引用了一个无效的指针。&*p
是否在技术上构成无操作或者是解引用后跟随一个取地址符,存在一定的争议。 - Tyler McHenryarray[10]
相当于 *(array + 10)
(也相当于 10[array]
),所以 &array[10]
的作用类似于从 *(array+10)
中删除 *
。任何像样的编译器都应该生成相同的代码(并发出相同的警告)。
这实际上是一个相当简单的问题。
你所做的只是指针数学运算,没有任何无效的地方。如果您尝试以某种方式使用生成的指针,则取决于您的进程是否可以访问该指针指向的内存,如果可以,则其权限是什么?
foo.cc:
#include <iostream>
using namespace std;
int main() {
int array[10];
int *a = array + 10;
int *b = &array[10];
int *c = &array[3000];
cerr << "Pointers values are: " << a << " " << b << " " << c << endl;
return 0;
}
编译:
g++ -Werror -Wall foo.cc -o foo
应该不会出现警告,因为 int *b = &array[10] 是有效的
实际上,我添加的后续行也指出了指针运算的一些内容。
不仅 foo 能编译通过,而且还能毫无问题地运行:
./foo
Pointers are: 0x7fff1d356e68 0x7fff1d356e68 0x7fff1d359d20
#include <stdio.h>
int main() {
int array[10];
int *a = array + 10;
int *b = &array[10];
int *c = &array[3000];
fprintf(stderr, "Pointers are: %p, %p, %p\n" , a , b , c );
return 0;
}
然后:
gcc -std=c99 -Wall -Werror -o foo foo.c
./foo
输出:
Pointers are: 0x7fff2c7d22c8, 0x7fff2c7d22c8, 0x7fff2c7d5180