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


那我们就发明一个,比如想把 p 所指向的那块内存的值改为 999,可以这样写 。
*p = 999;
这里的 * 就表示"指向"的含义,即 *p 不是说 p 这个变量的内存地址,而是把 p 这个变量里存的内容当做内存地址来看,指向这个内存地址 。
用图表示就是:

你管这破玩意叫指针?

文章插图
 
所以连起来一个完整的程序就是:
short a = 1234;
// 指针的定义
short * p;
// 指针的初始化,也即指针变量本身的值
p = &a;
// 指针变量所指向的内存地址的值
*p = 999;
执行过后,a 的值会变成 999,或者说 6 号格子与 7 号格子里的值会变成 999 。
5. 指针的加减
如果对一个普通变量 +1,比如说:
int a = 1;
int b = a + 1;
那显然,b 的值应该是 2,毫无疑问 。
但是如果对一个指针变量 +1,会怎么样呢?
int a = 1;
int *p = &a;
int *p2 = p + 1;
我们假设变量 a 放在了格子 1 处 。
变量 a 的值是什么,以及变量 p 被放在了哪里,我们都不关心,就只盯着 p 的值看,显然,一开始的时候是 1 。
(为方便演示,下面的图直接表示 p 所指向的内存地址,而不是 p 本身所在的内存地址)
你管这破玩意叫指针?

文章插图
 
我们先不考虑,p + 1 应该是几,如果让你来设计这个语言,你觉得 p + 1 是几比较好呢?
我认为,只有两种较为合理的设计 。
第一种,p + 1 就等于 2,就简简单单当做数值进行加法运算而已 。
你管这破玩意叫指针?

文章插图
 
第二种,p + 1 等于 5,即跨过一个 p 所指向的内存单元的数据类型的大小,也就是 4 字节的 int 。
你管这破玩意叫指针?

文章插图
 
你觉得那种比较合理呢?
那显然是第二种嘛!不然和普通变量有啥区别了,你既然设计出了指针变量这个玩意,就需要让它发挥点方便程序员的作用,这才是你设计它的真正目的 。
当然你不服,你就想让这个 int * 类型的指针变量,就真真正正在数值上只 +1,也就是让 p 等于 2,该怎么办呢?
很简单,分成三步就好了:
第一步,把 int * 类型的 p 强转为 char * 类型的 p 。
你管这破玩意叫指针?

文章插图
 
第二步,p + 1 。
你管这破玩意叫指针?

文章插图
 
第三步,再把 char * 类型的 p 强转为 int * 类型 。
你管这破玩意叫指针?

文章插图
 
完事!用代码表示就是:
p = (int *)((char *)p + 1);
你会看到,C 语言项目中经常使用这样的玩法 。
当然,你这一顿花里胡哨的操作,在 CPU 眼里,就是对一个内存地址处的值简简单单地 +1 而已 。
五、指针的本质
我们看上面的一张图:
你管这破玩意叫指针?

文章插图
 
其实,别看上面又 short * p 又 short a 的,这是给程序员和编译器看的 。
在 CPU 眼里,根本没有这些眼花缭乱的标签,以及五花八门的解读,就是 0 ~ 4 号格子里存了个数字 6,然后 6 ~ 7 号格子里存了个数字 1234,仅此而已 。
更进一步讲,其实就只是 1 号格子里存储了数字 6(234 号格子是空的),6 号格子里存储了数字 12,7 号格子里存储了数字 34 。


推荐阅读