指向数组末尾之后位置的C++指针代码是否符合标准?
关于C++数组指针越界的标准合规性与运行问题解答
先贴出你提供的代码:
#include <iostream> int main() { int arr[4]{0,1,2,3}; int* begin = arr; int *end = &arr[4]; int *firstElement = &arr[1]; int *lastElement = &arr[3]; int *onePastEnd = &arr[5]; std::cout << firstElement - begin << std::endl; //outputs 1 std::cout << lastElement - begin << std::endl; //outputs 3 std::cout << end - begin << std::endl; //outputs 4 std::cout << onePastEnd - begin << std::endl; //outputs 5 //std::cout << (*(firstElement - begin)); //illegal indirection because you're trying to find out what is at an address, but this is not an address rather difference between two pointers }
1. 代码是否符合C++标准?
要分两种情况明确:
&arr[4]是符合标准的:C++标准允许创建指向数组最后一个元素之后一个位置的指针(俗称“one past the end”指针),这个指针可用于标记范围边界(比如和起始指针配合计算元素个数),但注意该指针绝对不能被解引用。&arr[5]完全不符合标准:数组arr仅含4个元素,合法索引为0~3。arr[5]本身属于越界访问,获取它的地址属于创建超出允许范围的指针,直接违反C++标准,属于未定义行为。
另外,onePastEnd - begin这个指针减法操作也属于未定义行为,因为onePastEnd是非法指针,标准仅允许指向同一数组(或其one past the end位置)的指针做减法运算。
2. 为何代码能“正常运行”?
未定义行为的核心是C++标准不对其行为做任何承诺,这段代码能运行只是巧合:
- 从内存布局看,数组
arr位于栈上,它后面的地址可能是栈上的空闲空间或其他变量内存,当前程序访问这些地址时没有触发内存错误(比如段错误)。 - 默认优化等级下,多数编译器不会主动检测这类越界指针的创建,因此代码能通过编译并运行。
但这种“正常”完全不可靠,更换编译器、调整优化等级、修改程序其他部分,都可能导致程序崩溃、输出错误结果,甚至出现更诡异的行为,绝对不能依赖未定义行为的表现。
内容的提问来源于stack exchange,提问作者ZoomIn
相关产品推荐
相关产品推荐

