三、一级指针 1. 指针的使用: 32位系统下是 4 个字节,64位系统下是 8 个字节
1)在定义的时候用 * 号,代表这个变量那个是指针类型 int a = 10; //定义一个整型变量,存储整数 10 int *p = &a; //定义一个整型指针变量,存储a的地址
2)在配合表达式使用 * 号,代表取值运算符,可以取出这个地址里的值 printf("%d\n", *p); // 打印p指向的地址里的值 printf("%d\n",*(&a)); // 打印a这个地址里的值 printf("%d\n", *p + 1); // 取出值,再加1打印出来
2. 指针的几种特殊定义方式:
1) int * const p; 指针常量:p 是 int*类型,那么const修饰的是p,所以p是常量,表示p指向的地址不可修改, 也就是说,p不能再指向别的地方了,但是可以修改p指向的这个地址里的值。 举例: int a = 10; int b = 20; int * const p = &a; p = &b; //错误 *p = 100; //允许
2) const int *p; int const *p; 常量指针:p 是 int*类型,那么const修饰的是*p,所以*p是常量,表示p指向的地址里的值不可修改, 也就是说,p里的值不能再重新赋值了,但是可以修改p指向的地址。 int a = 10; int b = 20; const int *p = &a; p = &b; //可以 *p = 100; //错误
3) const int * const p; 常量指针常量:p 是 int*类型,那么const分别修饰了p 和 *p,所以p和*p都是常量,表示p指向的地址不可修改, 同时p指向的地址里的值也不可修改。 int a = 10; int b = 20; const int *const p = &a; p = &b; //错误 *p = 100; //错误
《C Primer Plus》 : "自由的代价,是永远的警惕。" 你定义了一个指针,那就一定要知道这个指针指向的什么地方,而且你要保证这个指针是真实有效的,否则我就用程序崩溃来惩罚你。
四、多级指针
#include <stdio.h> int main(void) { int a = 10; int *p = &a; //定义一个一级指针变量,存储了整型变量a的地址 int **pp = &p; //定义一个二级指针变量,存储了整型一级指针变量p的地址 int ***ppp = &pp; //定义了一个三级指针变量,存储了整型二级指针变量pp的地址
printf("%p, %p, %p, %p\n", &a, &p,&pp, &ppp); // 分别打印各个变量自身所在的内存地址
printf("%p, %p, %p, %p\n", &a, p, pp, ppp); //printf("%d", a); 用%d的形式打印a的值:整数 //printf("%p", p); 用%p的形式打印p的值:地址 // &a : 打印 变量 a 的地址 // p:打印变量 a的地址 // pp: 打印变量 p 的地址 // PPP:打印变量 pp 的地址
printf("%p, %p, %p, %p\n", &a, p, *pp,**ppp); // &a : 打印 变量 a 的地址 // p:打印变量 a 的地址 // *pp:打印变量 a 的地址 //**PPP: 打印变量 a 的地址
printf("%d, %d, %d, %d\n", a, *p, **pp, ***ppp); // a: 打印 10 // *P: 打印 10 // **pp:打印 10 // ***ppp: 打印 10 }
五、指针 和 数组的用法
int num[5] = {10, 20, 30, 40, 50}; int *p = num;
打印的值 打印后*p的值是 数组里的原值 // 操作地址 *p++ 10 20 10 *(p++) *和++的优先级相同,根据结合性(从右往左),那么p先和后自增运算符++结合, ++操作将在表达式完成后进行自增,也就取出p指向的值之后,p指向的下标后移一位(4个字节)。
*++p 20 20 10 *(++p) *和++优先级相同,根据结合性(从右往左),那么p先和前自增运算符++结合, ++操作将会立即完成,p指向的下标后移一位(4个字节),然后再取出p指向的值。
// 操作数值 (*p)++ 10 11 11 根据优先级()小括号优先级最高,p先和*相结合,然后再和后自增运算符++结合, 因为是后自增,所以先打印当前下标的值,然后在原值的基础上自增 1,此时原值已被改变
++*p 11 11 11 ++(*p) 根据结合性/优先级,*和p先结合,然后再和前自增运算符++结合, 因为是前自增,所以先在原值的基础上自增1,然后在打印这个值,此时原值已被改变。
总结:如果一个表达式里有多个运算符,则先进行优先级比较,先执行优先级高的运算符; 如果优先级相同,那就看结合性,根据结合方向来做运算。
结合性: 从左往右: 小括号()、数组括号[]、成员选择 . 和 ->,双目运算符,逗号运算符
从右往左: 单目运算符、三目运算符、赋值类运算符
/* ++a: 是直接从变量 a 所在的内存地址中取值,并进行加1操作,再执行表达式剩余部分。 a++: 先把变量的值保存在一个临时寄存器里,然后再执行整个表达式,执行完之后,再把a的值自增1,再返回内存里。
CPU -》 寄存器 -》 缓存(L1\L2\L3) -》来自于内存 CPU只和寄存器做数据交换,对于重复操作的数据会放在缓存里。 但是不管寄存器还是缓存,他们的数据都来自于内存。 */
未完待续,请看下一篇《C语言核心知识点相关总结(三)》
|