int main(void) { int a[5] = {1, 2, 3, 4, 5}; int *ptr = (int *)(&a + 1); printf("%d %d", *(a + 1), *(ptr - 1)); return 0; }
一个指针它由 2 个要素组成:
(1)指针的值。也就是地址,更通俗的说就是指针所指的东西在哪。
(2)指针的类型。也就是指针所指的东西是什么,编译器就是依据指针的类型,来对指针所指的那块内存进行解释的。也正是这个类型,决定了对一个指针执行 +1 操作时,指针到底该偏移多少个字节。
int a[5] = { 1, 2, 3, 4, 5 }; auto *p1 = a; // auto是C++11特性 auto *p2 = &a; cout << p1 << " " << p2 << endl; cout << *(p1 + 1) << " " << *((int*)(p2 + 1) - 4) << endl;
上述程序执行时,你会发现p1
和p2
打印的内容完全一致,这只能说明它们的第一个要素相同。事实上它们的第二个要素,即指针的类型不同,p1 指向的内存是一个 int,大小 4 字节;p2 指向的是一个 int[5] 数组,大小 4 * 5 = 20 个字节。理解了这些,其他就很好理解了,比如为什么*(p1 + 1)
得到 2,*((int*)(p2 + 1) - 4)
得到的也是 2。
&a==a
&a+n==a+n*sizeof(a)
a+n==a+n*sizeof(a[0])
sizeof(a)==数组长度*sizeof(*a)==数组长度*(a[0])
sizeof(&a)==sizeof(int (*)[])==4 (x86的指针长度)
type *p;
...
p+n—>p+n*sizeof(*p)
type x;
&x+n—>&x+n*sizeof(x)
不过上面的仅供记忆,实际上(当然不同操作系统/编译器也可能会有影响)不同类型的+1或+n生成的汇编代码和机器码是不同的。而sizeof的实现恰恰是基于+1操作的,而不是反过来,有兴趣可以自行搜索