地址和取址
在了解指针之前,我们不得不谈一个东西,那就是地址和取址
在计算机中,存储的方式其实只有一个,不管是二维数组、三维数组(这里不讨论,下次可能专门写一篇讲一维数组和二维数组之间存储的联系),还是什么抽象的东西也好,其实遵循的道理都是一样的。
下面我们就来好好看看计算机里面的存储和地址
其实计算机里数据都是以这样的方式存储的,
没错,就是这样的一长条的链子,一条链子上有很多很多的位子,每一个位子上放入一个数据,我们暂且把这种存储方式称为顺序存储
那么在这些位子上放入数据之后,我们还会对每一个位置进行编号,编号和位子是一一对应的,不会改变的。
如果这样还不足够清晰简洁,那我们再来看一看下面这个例子
我们现在把计算机的存储方式抽象成用 ”坑“ 的方式来理解。
数据和存储空间就是萝卜和坑的关系,数据1,2,3分别是萝卜1,2,3。01,02,03就是坑的地址,是不会变的,01号坑就永远是01号坑,你看起来它变了,只是因为里面的萝卜换了。
萝卜的位置可以换来换去,但是坑的编号和坑的位置是永远一一对应的。
(画的很丑hhh,见谅!)
现在我们来做一个换萝卜的小游戏
现在我们把01号坑里的萝卜1,放到02号坑里,然后把02号坑里原来的萝卜2放到01号坑里
代码如下:
#include <stdio.h>
int main()
{
int a=3,b=4;
printf("交换前a和b的值为:%d,%d\n",a,b);
printf("a的地址为:%p\nb的地址为:%p\n",&a,&b);
swap(&a,&b);
printf("交换后a和b的值为:%d,%d\n",b,a);
printf("a的地址为:%p\nb的地址为:%p\n",&a,&b);
}
在这段代码中,a,b 就是 01坑 和 02坑,而3,4就是萝卜1,2
其中 & 符号就是我们常见的 取址符 , &a 的意思就是获取a的地址,即得到 01号坑 的编号 01
因此显而易见,swap的功能就是找到01号坑和02号坑,然后将里面的萝卜进行调换
好了,说了这么多,如果我们的理论正确,那么我们预测的实验结果就是,01号坑和02号坑的编号不变, 01号坑里放着萝卜2, 02号坑里放着萝卜1
即a和b里面的数值进行了调换,但是a和b的地址是不变的,因为坑和编号是一一对应的。
好的,那我们来看看实验结果:
现在我们的结论被验证了,说明了计算机存储的方法确实是和我们想象的一样的。
那我们再来进一步讨论
由于计算机的内存和单个数据来比较要大的多,也就是说,这里可能有成千上万个坑位,但是你手上只有两个萝卜,如果是这样,那么每一次程序重新运行,都会重新申请内存。
也就是说,每一次程序重新运行时,就是你拿着你的萝卜重新找坑放进去,由于计算机还有其他程序在运行,因此你是一直在走动的,当我们写的这个程序开始运行时,你走到哪里你就要在哪里找坑把萝卜都放进去。
又因为坑有这么多,而萝卜只有两个,因此每一次你放萝卜的坑基本上都是不一样的。
我们来再一次运行前面的代码:
结果如下:
显而易见的,我们的理论又一次被验证了。
好了,这样要注意的点就这几个:
- 变量是 坑
- 数据是 萝卜
- &变量是 编号(地址)
- 地址采用十六进制的数字显示。
指针
接下来我们就可以引入我们的正题——指针
先摆上一些定义:
指针是一种特别变量,全称是指针变量,专用于存放其它变量在内存中的地址编号,指针在使用之前要先声明。
语法是:
datatype *varname;
datatype 是指针的基类型
它必须是一个有效的C数据类型(int、char、double或其它自定义的数据类型)
varname 是指针的名称。用来声明指针的星号 * 与乘法中使用的星号是相同的。
但是,在这个场景中,星号是用来表示这个变量是指针。
以下是有效的指针声明:
int *ip;