指针
结束了函数的学习,我们进入了 C 语言最经典的核心内容,指针的学习,指针的概念理解比较复杂,使用起来也比较灵活,但是指针是 C 语言的灵魂,只有学会如何使用指针,才能算是学会了 C 语言。
引入指针
在引入指针之前,我们需要知道,数据在内存中
是如何存储和读取
的,这样才能帮助我们
更好的理解指针
这个概念。
数据在内存中的存储和读取
程序定义了一个变量
,在程序编译时
,就会给这个变量分配内存单元
。至于内存单元的大小
,是变量类型决定
的。在 Visual C++ 中,为整型分配4个字节,单精度浮点型分配4个字节,对字符型变量分配1个字节。
内存区的每一个字节都有一个编号,这就是地址
。你可以理解为存储柜的箱号
,在地址所标志的内存单元中
存放的数据则相当于箱子内寄存的物品
。
现在,有了地址,我们就能通过地址找到所需要的变量单元,我们就说地址指向该变量单元
。我们举个例子:
内存是一个大的寄存柜,一个柜子上写着2008号柜,这个2008就是这个柜子的地址。或者我们说2008指向这个柜子
。
因此,我们形象的把地址称为指针
。也就是通过指针,我们就能找到它为地址的内存单元。
存储单元的地址和内容
我们知道了指针就是指向存储单元的地址的时候,就引出了两个概念,就是存储单元的地址和存储单元的内容,请不要混淆。我们来句个例子:
1 | int a=1, b=2, c=3; |
上面我们声明并定义了三个变量 a b c ,那么在编译时,编译器发现 a、b、c 都是整型,所以:
把2000~2003四个字节分配给了变量 a
把2004~2007四个字节分配给了变量 b
把2008~2011四个字节分配给了变量 c
注意,在不同的编译器和不同次的编译中,分配给变量的内存地址是不同的。
1 | int a=1, b=2, c=3; |
然后我们将变量 a 打印出来,这个过程大概是这样的。先通过变量名 a 来找到存储单元的地址,然后通过地址在找到存储单元中的数据。因为在程序编译时,编译器把变量名都改成了变量地址。所以对数据的存取都是通过地址来进行的。
1 | int a=1, b=2, c=3; |
如果此时有一个输入值到了变量 b ,我们知道变量 b 的存储地址是2004~2007,那么键盘输入的值就会送到2004~2007这个存储单元。
1 | int a=1, b=2, c=3; |
如果又加了一句 c=a+b
,就会从 a 所在的2000~2003地址取出 a 的值,再从 b 所在的2004~2007取出 b 的值,然后将 a、b 的值相加,的得到的结果再送到 c 所在的2008~2011这个地址去。
我们称这种根据变量名进行的访问
,叫做直接访问
。
间接访问
我们说通过变量名访问存储单元叫做直接访问
,还有一种叫做间接访问
。我们知道指针是指向数据的地址,那么我们如果把某一变量 a 的地址存放在一个变量 b 中,然后通过变量 b 来找到变量 a 的地址,然后根据地址访问变量 a,我们称这种访问方式为间接访问
。
我们知道,在 C 语言中,可以定义很多种类型的数据,例如整型、浮点型、字符型等等。这种存放内存地址的变量
我们称之为指针变量
,我们先看一个例子:
1 | i_pointer=&a; |
因为 a 的地址是2000~2003,所以现在 i_pointer 的地址为2000,也就是变量 a 所占用单元的起始地址
。
那么现在两种方式都可以访问 a 这个变量了:
- 先从 i_pointer 找到 a 的地址,然后根据地址间接访问
- 直接通过 a 变量名找到地址,然后直接访问。
1 | i_pointer=&a; |
上面个的
* i_pointer
就是 a 地址所指向的对象,也就是 a 的存储单元本身,所以我们就可以直接赋值 3 了,这样和a = 3
的效果是一样的。
我们可以这么说,指针就是可以找到以它为地址的内存单元。所以,一个变量的地址就是该变量的指针
,如果一个变量专门存放其他变量的指针,我们就称之为指针变量
。
注意
指针和指针变量是两种东西,指针就是指地址,比如 a 的地址是2000,而指针变量真的是变量,是用来存放指针的那个变量。
尾巴
这是我的个人学习笔记,主要是应付考研复习使用,充斥着一些吐槽和个人观点,并不严谨,欢迎大家参考、指正。