8-1. 初识指针

  • 学习人数 30K+
  • 适合所有人群学习
avatar
林耿亮

你好编程主讲老师

1. 内存地址

讨论什么是指针之前,我们先了解一下什么是内存地址?

1.1 CPU与内存协同工作

在之前的章节中,我们已经熟练地使用C语言中的各种数据对象了。

以整型加法为例,我们来看看在计算机内部,CPU(中央处理器)是如何配合其他硬件进行计算的。

CPU由三部分构成:

  1. 算术、逻辑单元:对数据执行运算(例如加法、减法)的电路。
  2. 控制单元:协调机器活动的电路。
  3. 寄存器组 :数据临时存储。

什么是计算机语言_CPU内部结构

然而,寄存器能够存储的信息量很少,仅仅是当前工作所必要的。话说鱼的记忆只有7秒,CPU的记忆恐怕是更短。总不能,CPU做一步操作,就把上一步操作的结果给忘了吧。

因此,我们需要内存来配合CPU进行数据操作。

内存条

数据几乎都存储在内存上,仅有当前正在处理的数据,才放到CPU的寄存器组上,等待CPU进行计算。CPU将数据计算完毕后,再存储到内存中。数据通过数据总线,在CPU和内存上进行传输。

什么是计算机语言_CPU-总线-内存

接下来,我们来看看,将两个数据相加会经历哪些步骤。

  1. 从内存中取出一个加数放到一个寄存器中。
  2. 从内存取出另一个加数,放到另一个寄存器中。
  3. 激活算术、逻辑单元中的加法电路,将前面两步的寄存器作为输入,用另一个寄存器存放结果。
  4. 将结果存放到内存中。

CPU加法步骤

1.2 访问内存中的“房间”

只有正在被处理的数据才会被放到CPU的寄存器上,等待CPU进行计算,CPU将数据计算完毕后,再存储到内存中。所以,内存才是数据的大本营。

我们知道,计算机通过晶体管的开关状态来记录数据。它们通常8个编为一组,我们称之为字节。既然内存需要存储数据,内存上必然有非常多的这种8个开关组成的编组。

我们可以把这种编组看作居住数据的“房间”,而为了方便地找到这些“房间”,每个“房间”均有一个编号。第一个“房间”编号从0开始,此后依次加1。

内存房间

我们把“房间号”,称之为内存地址。

就像生活中我们所说的:“AA大街,BB公寓,123房间一样”。只不过在内存中没有大街和公寓,仅需要编号即可表示地址了。

1.3 基础数据类型怎样居住“房间”

那么,我们先研究一下,基础数据类型,怎样居住这些“房间”吧。

数据类型 大小
char 1
short 2
int 4
long 4
long long 8
float 4
double 8

似乎,除了char可以住下一个房间。其他的数据类型都需要住多个房间。

住几个房间

既然这样,我们怎样表达一个数据类型,当前住在哪一些房间内呢?

int居住房间的表示方式

以int为例,我们有以下两种表达方式:

  1. 列举所有的房号:301,302,303,304。
  2. 首房间及房间数:从301开始的4个房间。

对于int还好,仅需要4个“房间”。如果数据需要的“房间”很多,第一种方式需要保存更多的“房间号”。很显然第二种方式更为灵活。

计算机使用第二种方式记录一个数据对象在内存中的存储位置。

我们把第一个“房间”的“房间号”,称为这个数据对象的首地址。那么数据对象需要的房间数量,就是它所占用的存储空间大小。

因此,记录一个数据对象在内存中的存储位置,需要两个信息:

  1. 数据对象的首地址。
  2. 数据对象占用存储空间大小。

2. 指针数据类型

2.1 取地址运算符 &

现在我们认识一个新的运算符——取地址运算符&。

取地址运算符是一个一元运算符,写在一个数据对象的左边,可以获取一个数据对象的首地址和所需存储空间大小

int n;
类型 pn = &n; //  获取数据对象n的首地址和所需空间大小

变量pn,存储了变量n的首地址和所需空间大小,那么通过变量pn可以在内存中找到变量n

所以,变量pn到底是什么类型呢?

2.2 声明指针类型的变量

int n;
int* pn = &n;

char c;
char* pc = &c;

声明指针的公式:

声明指针的公式

int* pn声明一个保存了int类型的首地址大小的变量。

char* pc声明一个保存了char类型的首地址大小的变量。

变量pn存储了变量n的首地址与大小,变量pc存储了变量c的首地址与大小。通过pnpc可以在内存中找到变量nc

定义: 设一个数据对象为x,设另一个数据对象为pp存储了x的首地址和所占空间大小。那么,p称之为x的指针,或者说p指向x

对于上面的代码: pn被称作n的指针,或者说pn指向npc被称作c的指针,或者说pc指向c

int* pn;    //  将空格放在变量旁
int *pn;    //  将空格放在类型旁
int*pn;     //  不用空格

另外,声明指针变量时,将空格放在变量旁或者将空格放在类型旁,甚至不用空格。这3种写法都是可以的。