简介
指针一直是C语言和C++语言最难理解的一部分,无论是C语言和C++语言,复杂的数据结构都是离不开指针的运用,所以必须掌握好指针这个数据类型,你才能够在阅读框架代码时,游刃有余。今天我们从指针的本质来重新理解指针这个数据类型。
1.指针的本质
指针是用来保存地址的一个变量,那么变量都是保存在内存中,而内存其实就是一组有序字节组成的数组,每个字节有唯一的内存地址。CPU 通过内存寻址对存储在内存中的某个指定数据对象的地址进行定位。说白了,CPU就是通过地址去查找存储在内存中的数据。下面我们看看如下示意图:
这是一个 4GB 的内存,可以存放 2^32 个字节的数据。左侧的连续的十六进制编号就是内存地址,每个内存地址对应一个字节的内存空间。而指针变量保存的就是这个编号,也即内存地址。指针本身也是有内存地址来保存这个变量的。
2.为什么要使用指针
在C语言中,指针的使用非常广泛,因为使用指针往往可以生成更高效、更紧凑的代码。总的来说,使用指针有如下好处:
1)指针的使用使得不同区域的代码可以轻易的共享内存数据,这样可以使程序更为快速高效;
2)C语言中一些复杂的数据结构往往需要使用指针来构建,如链表、二叉树等;
3)C语言是传值调用,而有些操作传值调用是无法完成的,如通过被调函数修改调用函数的对象,但是这种操作可以由指针来完成,而且并不违背传值调用。
3.指针定义和初始化
下面我们再来看看下面例子:
int a = 100;
int *p = &a;
int **p2 = &p1;
p2 p1 a
&p1 -> &a -> 100
为了方便理解,我们来打个比喻:
定义的a,p,p2都是一个盒子,他们都有自己地址空间,方便别人找到它
a是一个盒子,用来装100这个数据,a本身有地址;
p也是一个盒子,用来装a的地址,p本身也有地址;
P2也是一个盒子,用来装p的地址,p2本身也有地址;
a和p和p2变量本身都是代表盒子里面的东西
=》盒子里面装可能是值,也可能是地址,例如a就是值,p和p2都是地址;
“*”的操作(只对指针变量),就是取出盒子里面地址,去打开另一个盒子那东西
=》相当于,从抽底里面取出一把钥匙,去打开另一个抽底去拿东西一样。
指针的声明比普通变量的声明多了一个一元运算符 “*”。运算符 “*” 是间接寻址或者间接引用运算符
总结如下:
3.1.指针也是一种数据类型,也占用内存空间
1) 指针是用来干嘛?
=>指针是用来存放地址的, 这个地址(p=&a)可以指向"int"型内存空间
例如定义:int a;//我们知道a是用来存储整型数据的
例如再定义int *p; //那么,指针也是一种数据类型,也可以用来定义变量
2)指针本身也有地址,也占用内存空间
=>指针定义时(int *p)不占用内存空间,当其赋值(p=&a)时分配内存空间
3.2.一级指针: p 和 *p区别
"p"操作:
其实就是直接取出它内存空间里面值(只不过指针变量p存储空间存放的是一个地址);
"*p"操作:
第一步,p操作,先去取出p存储空间里面的地址(p存储的是一个地址);
第二步,*P操作,再把这块地址里面值取出来;
3.3.二级指针: p2 和 *p2 和 **p2操作顺序
第一步: p2, p2操作,先取出p2内存空间里面值,得到的这个值是一级指针的地址;
第二步: *p2, 再*p2操作, 取出一级指针内存空间里面的值(一级指针内存空间里面的值还是个地址,例如变量a地址);
第三步:**p2, 再**p2操作, 得到变量a的值;
#include "iostream"using namespace std;void main(){ int a = 100; int *p = &a; int **p2 = &p; //int ***p3 = &p2; //1.取值, 打印 printf("取值, 打印:%d, %d, %d\n", a, *p, **p2); //2.取地址, 打印 =>指针也是有地址的 printf("取地址, 打印:&a=%#x, &p1=%#x, &p2=%#x\n",&a, &p, &p2); //3.打印地址,对比 //=>p 和 &a打印都是同样地址,因为p是用来存放a的地址 printf("打印地址,对比:p=%#x, &a=%#x\n", p, &a); //p2 和 &p打印都是同样地址,因为p2用来存储&p地址 //=>*p2 和 &a打印都是同样地址,因为*p2取就是p存储单元里面值(即使a地址) printf("打印地址,对比:p2=%#x, &p=%#x ,*p2=%#x, &a=%#x\n", p2, &p, *p2, &a); system("pause"); return;}
最后输出结果:
推荐阅读:
专辑|C++专辑
专辑|Camera专业知识
专辑|摄像头行业动态
专辑|程序人生