首先看下生活中的快递柜:
这里的格子就是内存单元,编号就是地址,格子里放的东西就对应存储在内存中的内容。
假设我把一本书,放在了 03 号格子,然后把 03 这个编号告诉你,你就可以根据 03 去取到里面的书。那如果我把书放在 05 号格子,然后在 03 号格子只放一个小纸条,上面写着:「书放在 05 号」。
你会怎么做?当然是打开 03 号格子,然后取出了纸条,根据上面内容去打开 05 号格子得到书。这里的 03 号格子就叫指针,因为它里面放的是指向其它格子的小纸条(地址)而不是具体的书。明白了吗?那我如果把书放在 07 号格子,然后在 05 号格子 放一个纸条:「书放在 07号」,同时在03号格子放一个纸条「书放在 05号」
这里的 03 号格子就叫二级指针,05 号格子就叫指针,而 07 号就是我们平常用的变量。依次,可类推出 N 级指针。
所以你明白了吗?同样的一块内存,如果存放的是别的变量的地址,那么就叫指针,存放的是实际内容,就叫变量。
int a;
int *pa = &a;
int **ppa = &pa;
int ***pppa = &ppa;
上面这段代码,pa就叫一级指针,也就是平时常说的指针,ppa 就是二级指针。
内存示意图如下:
不管几级指针有两个最核心的东西:
指针本身也是一个变量,需要内存去存储,指针也有自己的地址
指针内存存储的是它所指向变量的地址
怎么去解读int a这种表达呢?int ** a 可以把它分为两部分看,即int 和 a,后面 a 中的表示 a 是一个指针变量,前面的 int 表示指针变量a只能存放 int 型变量的地址。对于二级指针甚至多级指针,我们都可以把它拆成两部分。首先不管是多少级的指针变量,它首先是一个指针变量,指针变量就是一个*,其余的表示的是这个指针变量只能存放什么类型变量的地址。比如inta表示指针变量 a 只能存放int 型变量的地址。
一个测试的例子如下:
int main()
{
int a =10;
int *p1 = &a;
int **p2=&p1;
int ***p3=&p2;
cout << "========================" << endl;
cout << "&a -----" << &a<<endl;
cout << "========================" << endl;
cout << "*p1 -----" << *p1 << endl;
cout << "p1 -----" << p1 << endl; // 和a地址相同
cout << "========================" << endl;
cout << "**p2 -----" << **p2 << endl;
cout << "*p2 -----" << *p2<< endl; // 和p1地址相同
cout << "p2 -----" << p2 << endl;
cout << "========================" << endl;
cout << "***p3-----" << ***p3 << endl;
cout << "**p3 -----" << **p3 << endl; // 和*p2、p1地址相同
cout << "*p3 -----" << *p3 << endl; // 和p2地址相同
cout << "p3 -----" << p3 << endl;
}
输出结果:
========================
&a -----0055FACC
========================
*p1 -----10
p1 -----0055FACC
========================
**p2 -----10
*p2 -----0055FACC
p2 -----0055FAC0
========================
***p3-----10
**p3 -----0055FACC
*p3 -----0055FAC0
p3 -----0055FAB4