数组的首元素地址和数组地址在数值上是相同的,但是它们所表示的意义却不相同:
1、数组的首元素地址:
数组名 表示数组的首元素地址,该值是一个指针常量,不能被修改。
引申:指针常量和常量指针的区别
1)指针常量——指针类型的常量(int *const p)
本质上一个常量,指针用来说明常量的类型,表示该常量是一个指针类型的常量。在指针常量中,指针自身的值是一个常量,不可改变,始终指向同一个地址。在定义的同时必须初始化。
int a = 10;
int b = 12;
int* const p = &a; // 定义指针常量,指向int a的地址
*p = 100; // 正确,指向的内存地址中数据可以修改
p = &b; // 错误,指向的内存地址不可以修改
2) 常量指针——指向“常量”的指针(const int *p,int const *p)
常量指针本质上是一个指针,常量表示指针指向的内容,说明该指针指向一个“常量”。在常量指针中,指针指向的内容是不可改变的,指针看起来好像指向了一个常量。
int a = 10, b = 12;
const int *p = &a; //定义常量指针,指向int a的地址
*p = 20; // 错误,指向的内存地址中的数据不可以修改
p = &b; //正确,指向的内存地址可以修改
对比总结:
| 特性 | 指针常量(int *const ptr) | 常量指针(const int *ptr) |
|---|---|---|
| 指针的指向 | 不可变(固定初始化地址) | 可变(可指向其他地址) |
| 指向的数据 | 可通过指针修改 | 不可通过指针修改 |
| const的位置 | const在*右侧(修饰指针本身) | const在*左侧(修饰数据类型) |
记忆技巧:
从右向左读声明:
int *const p→p是常量(const),指向int(指针不可变)。
const int *p→p是指针(*),指向const int(数据不可变)。结合场景理解:
若需要固定指针的指向(如硬件寄存器地址),用指针常量。
若需保护数据不被修改(如字符串常量),用常量指针。
双重常量:
若同时约束指针和数据的不可变性,可声明为:
const int *const ptr = &a; // ptr不可变,指向的数据也不可变
此时,指针的指向和指向的数据均无法修改。
2、数组地址:
&数组名 表示在整个数组的地址。
代码部分:
#include <stdio.h>
int main()
{
int arr[10] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
printf("%d\n", sizeof(arr)); // 数组的整个大小 10 * 4 = 40
printf("%d\n", sizeof(&arr[0])); // 数组首元素的地址,一般看pc的位数,32位的为4,64位的为8
printf("%d\n", sizeof(&arr)); // &arr表示数组的地址,一般看pc的位数,32位的为4,64位的为8
printf("arr = %p\n", arr); // 表示数组的首元素地址
printf("&arr[0] = %p\n", &arr[0]); // 表示数组的首元素地址
printf("&arr = %p\n", &arr); // 表示整个数组的地址
printf("arr + 1 = %p\n", arr + 1); // 表示数组的的首元素地址偏移4字节
printf("&arr[0] + 1= %p\n", &arr[0] + 1); // 表示数组的首元素地址偏移4字节
printf("&arr + 1= %p\n", &arr + 1); // 表示数组的地址偏移40字节
printf("arr + 9 = %p\n", arr + 10); // 表示数组的首元素地址偏移40字节
return 0;
}
运行结果:
40
8
8
arr = 000000000061FDF0
&arr[0] = 000000000061FDF0
&arr = 000000000061FDF0
arr + 1 = 000000000061FDF4
&arr[0] + 1= 000000000061FDF4
&arr + 1= 000000000061FE18
arr + 9 = 000000000061FE18
3、总结
* 数组首元素地址可使用:数组名字,&数组名[0],两种方式表示,其+1表示指向数组的第二元素的地址。
* 数组地址使用:&数组名,其+1表示跳过整个数组的地址。

1815

被折叠的 条评论
为什么被折叠?



