数组名的地址
理解 int *ptr = (int *)(&a + 1); 需要掌握几个关键概念,我来一步步解释:
1. &a 的含义
a是数组名,类型是int[5](包含5个整数的数组)&a的类型是int (*)[5](指向"包含5个整数的数组"的指针)- 虽然
&a和a的内存地址值相同(都指向数组开头),但指针类型不同,这决定了指针运算的行为不同
2. 指针运算 &a + 1
- 指针运算的步长取决于指针指向的类型大小
&a的类型是int (*)[5],指向的是整个数组(大小为5 * sizeof(int)= 20字节)&a + 1:
在内存上跳过整个数组的大小(20字节)
指向数组末尾的下一个内存位置(即a[4]之后的位置)
内存示意图:
[ a[0] ][ a[1] ][ a[2] ][ a[3] ][ a[4] ] [ 下一个位置 ]
0x1000 0x1004 0x1008 0x100C 0x1010 0x1014
↑ ↑ ↑ ↑
&a a+1 &a+4 &a+1
3. 类型转换 (int *)
&a + 1的类型仍是int (*)[5](数组指针)(int *)强制转换:
将其转换为普通整型指针int*- 现在
ptr是一个指向整数的指针,但指向的是数组外的内存地址
4. 最终结果
int *ptr = (int *)(&a + 1);
ptr指向数组结束后的第一个内存位置- 但类型是
int*(而非数组指针),后续可按整型指针进行运算
结合代码验证:
printf("%d %d\n", *(a+1), *(ptr-1));
-
*(a+1):a是数组首元素地址(类型int*)a+1前进sizeof(int)= 4字节 → 指向a[1]- 值 =
2
-
*(ptr-1):ptr类型是int*,指向数组结束后的位置ptr-1后退sizeof(int)= 4字节 → 指向a[4]- 值 =
5
输出:2 5
关键区别总结:
| 表达式 | 类型 | 增加1的步长 | 指向位置 |
|---|---|---|---|
a |
int* |
4字节 | 首元素地址 |
&a |
int(*)[5] |
20字节(整个数组) | 数组地址(值同a) |
&a+1 |
int(*)[5] |
20字节 | 数组结束后的位置 |
(int*)(&a+1) |
int* |
4字节 | 同上(但类型改变) |
这个操作展示了C语言指针运算的类型敏感性:相同的地址值,不同的指针类型,会导致完全不同的算术运算结果。
浙公网安备 33010602011771号