为何两个C++指针表达式输出不同的内存地址?
问题
以下代码运行后输出了不同的内存地址,原本预期两个表达式返回相同地址,请问原因是什么?
#include <iostream> int main() { float (*arrayName)[2][4][4]; auto address1 = (**arrayName)[1]; // 0x10 auto address2 = (*arrayName)[1][0]; // 0x40 std::cout << "Address1: " << address1 << std::endl; std::cout << "Address2: " << address2 << std::endl; }
注:0x40是期望得到的地址,在线C++编译器测试时两者均输出0x10,但在RHEL7开发虚拟机中得到0x10和预期的0x40。
原因分析
1. 明确指针类型
float (*arrayName)[2][4][4]是一个指向三维float数组的指针,这个三维数组的维度是[2][4][4],每个float元素占4字节。
2. 拆解两个地址表达式
表达式(**arrayName)[1]的计算过程:
- 第一次解引用
*arrayName:得到整个三维数组[2][4][4],此时数组会自动退化为指向其第一个元素的指针——也就是指向[4][4]二维数组的指针(类型为float (*)[4][4])。 - 第二次解引用
**arrayName:得到第一个[4][4]二维数组,再次退化为指向其第一个元素的指针——也就是指向[4]一维数组的指针(类型为float (*)[4])。 - 最后
[1]:对这个一维数组指针做偏移,偏移量是1个[4]数组的大小(4个float × 4字节 = 16字节,即0x10),所以最终地址是原地址 + 0x10。
表达式(*arrayName)[1][0]的计算过程:
*arrayName是三维数组,退化为指向[4][4]二维数组的指针(类型float (*)[4][4])。(*arrayName)[1]:偏移1个[4][4]二维数组的大小(4×4个float ×4字节=64字节,即0x40),得到第二个[4][4]二维数组,随后退化为指向其第一个[4]一维数组的指针。[0]:偏移0个[4]数组,所以最终地址是原地址 + 0x40。
3. 不同环境结果差异的原因
代码中的arrayName是未初始化的野指针,没有指向任何有效的内存空间,这属于C++中的未定义行为——不同编译器、不同操作系统对未定义行为的处理逻辑可能完全不同,所以才会出现在线编译器和RHEL7虚拟机结果不一致的情况。
内容的提问来源于stack exchange,提问作者JacobGC
相关产品推荐
相关产品推荐

