你管这破玩意叫指针?( 二 )


movb $38, b
movw $999, c
movb $18, age
movl $2147483647, salary
当然,我还需要再通过这个标签,把我刚刚放进去的数据找出来 。
这很简单,但存在一个问题,放进去的时候,我们可以通过 movb,movw,movl 等知道占用多少个格子 。而取出来的时候,标签上可没有写这个数据占用了多少个格子,这是有问题的 。
因此,在定义这个标签时,不能光取个名字,还需要有个信息就是,这个标签对应的数据,占了多少个格子 。
我们就效仿刚刚的存放操作,也规定一系列单词,来修饰这些标签,表示占用了多少个格子 。
char 表示 1 个字节,short 表示 2 个字节,int 表示 4 个字节,long 表示 8 个字节 ...

你管这破玩意叫指针?

文章插图
 
于是乎刚刚的 5 个数据,就可以表示为如下指令:
char a = 29;
char b = 38;
short c = 999;
char age = 18;
int salary = 2147483647;
行了,我也别藏着掖着了,相信大家也知道,这里就是 C 语言的写法,而刚刚那堆 mov 是汇编语言的写法 。
这些 char a,char b,int salary 等,就是变量!记住,变量不但要有名字,还得有类型!
三、变量定义与赋值
其实,刚刚的写法,是把变量的定义与赋值操作写在一行了 。
比如有如下语句:
int a = 1;
实际上是分成两步的:
// 变量的定义
int a;
// 变量的赋值(此处也可以叫变量的初始化)
a = 1;
其中变量的定义是为了方便程序员后面去用它,这部分不是给 CPU 看的 。
你管这破玩意叫指针?

文章插图
 
而变量的赋值才是真正在内存中把数据放进去,这部分才真正涉及 CPU 具体指令的执行 。
你管这破玩意叫指针?

文章插图
 
也就是说,如果你仅仅定义了一个变量 int a; 但是没有给它初始化的赋值操作,那么最终在 CPU 执行指令的时候,这个定义根本就没有任何体现 。
四、指针
现在,让我们把内存清空,回到一开始的那一片净土上 。
你管这破玩意叫指针?

文章插图
 
我们来搞点花样 。我将我的密码(1234)存储在一个 short a 中,假设这个变量 a 被放在了 6 号格子处 。
你管这破玩意叫指针?

文章插图
 
同时,我将这个变量 a 的地址,也就是 6 这个数字,存储在另一个变量 int p 中,假设这个变量 p 被放在了 1 号格子处 。
你管这破玩意叫指针?

文章插图
 
这样,我寻找我密码的方式,就是先通过 p 所在的内存地址找到里面存的值,也就是 a 的内存地址 6,再通过 a 的内存地址找到里面存的值,也就是我要找的密码 1234 。
我们可以用下面的代码来表示刚刚的存放逻辑 。
short a = 1234;
// 假设 a 被放在了 6 号格子处
int p = 6;
这里的 p 和 a 都是变量,只不过,p 这个变量有点特殊,它里面存放的值是一个内存地址,我们把 p 这个变量形象地成为指针变量,简称指针 。
不过,这样有几个问题,我一个个来说 。
1. 取地址
首先,我们在编码阶段,无法知道也无需知道变量 a 会存放在哪里,不然就失去了标签的含义,又回到了需要关心具体的内存地址(也就是格子编号)的时代了 。
所以,我们应该有个方法,来在编码阶段表示变量 a 的地址的含义,姑且就叫做 &a 吧 。
那么我们的代码,就可以优化为:
short a = 1234;
// 假设 a 的地址是 6
// 那么下面的 p 就等于 6


推荐阅读