指针
理解指针
指针在c语言中就是一种变量用于存储地址的变量。与普通变量无异。
(1)就像 int a; 这就是定义了一个整型变量a,a变量是用于存储整型数据的。
(2)指针的定义,取决于你是用于存储那种类型地址的,比如
①存储整型的地址这样定义int *p
②存储浮点型的地址这样定义float *q
(3)那么地址是个什么样子的呢?地址其实就是内存空间的编号,我们在代码中编写的变量字符是不会被放入内存的,比如:
int a=20;
如上a=20,最后在内存中是没有a的,a只是在编译期间存在的,在内存中是这样存储的。
①在内存开辟(或找到)一个4字节(int是4字节)大小的空间,将20的二进制数放进去
②这个空间有个编号,也就是地址,这里的指针就是用于存储这个编号的(地址的)
指针就是存储上图紫色编号的(也就是地址),这就是为什么指针是面向内存层面的,只要把它(指针)指向的空间中的东西一改,内存中的数据不就改了。
声明指针
在上面也说过,存储什么类型的地址,就声明什么类型的变量(也就是指针)。只要在该变量前加个星号(*)就可以说明这个变量是存储该类型地址的指针了。
声明方式
int *a;//存储整型内存空间地址的变量,它的名字叫a(记住是叫a,不是*a,*相当于和int是一个“类型”的)
float *b;//存储浮点型内存空间地址的变量,它的名字叫b
其他类型就不用多bb了
取值
既然是指向内存的编号(地址),那它咋样取出那块空间里的值呢?
如上图指针中存储的是001,我们该如何取出20?
只要给地址前面加*,就是存储空间中的值的,也就是*001,输出后就是20,如果001被存储在某个指针中如p,那么*p就是20了。
赋值
前面说过指针可以取值,那么指针该如何赋值呢,指针是存储地址(也就是内存编号)的,所以只能将地址值赋给指针,可千万不能赋其他的东西。那么怎么将地址付给指针呢,&加变量名就是地址。
比如 int a=20;
int *p;
怎么将存储20的内存空间的地址给p呢,好的,p只能存储地址,那就给它地址,怎么给?&a就是,对应上图,a是20,&a就是001。再结合一下上面的取值,那么*p就又是20了。
&+变量名(数)=地址
*+指针变量(地址)=空间中的那个数
指针与数组
数组
数组是什么?数组就是存储同一类型的数据的“集合”,如int a[3],那么a数组就可以存储3个整型的数据。那么它们在内存中是什么样子的呢?比如:a[0]=100; a[1]=101; a[2]=102;
记住数组的所有元素都是连续的,必须是连续存放在内存中的。而且内存中只有编号(也就是地址)和存储空间的概念。a[0],a[1]这种东西只存在于编译期。
指针存储数组的地址
int *p,由前面可知,p是一个用来存储整型数据存储空间编号(也就是地址)的变量。那p可不可以存储030呢?答案是可以。那p可以不可以存储031呢?答案也是可以,自然而然032也是可以的。为什么呢?因为他们都是整型存储空间的地址,而p又恰好是存储整型存储空间地址的变量。
结合前一节的
&+变量名(数)=地址
*+指针变量(地址)=空间中的那个数
进行演示
存储方法:&+变量名(数)=地址
存储地址030:p=&a[0];//在数组中a[x]就相当于一个变量
存储地址031:p=&a[1];//在数组中a[x]就相当于一个变量
存储地址032:p=&a[2];//在数组中a[x]就相当于一个变量
取值方法:*+指针变量(地址)=空间中的那个数
地址为030的存储空间中的数:*p
地址为030的存储空间中的数:*p
地址为030的存储空间中的数:*p
代码截图
指针存储数组地址的一点点不同
1、如上面的int a[3],在数组中可以直接用一个数组名a来表示a[0]的地址,那么我们在给p赋值的时候可以直接p=a就可以了。(代替了p=&a[0])
2、在数组中可以通过地址+[数字]的方式来访问该地址所指向的存储空间中的数据。比如:地址1[0]:就是访问地址1所代表的空间中的数据,那么地址1[1]:就是访问地址1所代表的空间的下一个空间中的数据。
其实结合1、2可以看出数组的a就代表一个地址(地址存储在a中),那么a[x]可以访问到数据,凭什么我p[x]访问不到?当然可以访问到,毕竟我p中也存储了地址。
扩展
1、结合上面的分析看懂这个应该没问题。
2、其实地址也可以做加减运算,比如p中存储了一个地址,那么(p+1)就表示p的下一个地址,(p-1)就表示p的前一个地址。
自然而然*(p-1),*(p+1)是什么意思也就知道了。*+指针变量(地址)=空间中的那个数也可以通过(p-1)[0],(p+1)[0]取出。
指针与malloc函数
在创建链表或树的时候我们经常会遇到如下这样形式的代码
要想知道上面这句是什么意思,那得知道:
(1)sizeof函数是什么意思
(2)malloc函数是什么意思
(3)p中存储的是什么
由于上面涉及到了自定义结构体D,所以下面以整型数据说明,整型的会了,其它的自然就触类旁通了。
(1)sizeof(类型),将某类型传入sizeof,则会返回该类型在内存中所占空间的大小(以字节为单位返回)
(2)malloc(字节),malloc函数会根据程序员的需求在内存中开辟相应大小的存储空间,只需要程序员将空间大小传入即可(传入字节)。当malloc开辟好空间后就会将这个空间的地址给我们返回,我们只需要用相应类型的指针变量进行接收就可以了。
比如:malloc(4),则会开辟下面那个绿框框,然后将001返回。
(3)由上述可知,p中自然而然存储的就是地址喽。
说明
虽然malloc返回的是地址,但是它是什么类型的地址呢,该用什么类型的p接收呢?
之前就说过什么样类型的p接收什么样的地址,你malloc只返回一个泛泛的地址,我哪知道用什么样类型的p接收,于是就将malloc返回的地址根据我们的需求转成相应的地址。
如: (int *)malloc(字节)//将那个泛泛的地址转成整型的地址
(char *)malloc(字节)//将那个泛泛的地址转成字符型的地址
可以这样理解
malloc就是一个洗澡堂,里面出来一群光溜溜的人,你肯定不知道这些人是干什么的,但如果他们穿着衣服出来,你就会知道,哦原理这个是警察、那个是医生、他是农民工…
案例解释
第二行:因为malloc函数是在stdlib.h文件中的所以需要引入该文件
第三–六行:定义一个结构体,叫D,说白了就是自己创建了一种类型,类型的名称叫D,就像int、char一样。
第九行:声明存储D类型空间地址的变量。
第十一行:先用sizeof看看咱们自己定义的这个类型是几个字节,然后再给返回的地址穿个衣服(D*),最后用p接收这个地址。
指针获取结构体中的元素
书接上文,既然p里存储里结构体中的地址,我们怎样获取结构体存储空间中的值呢?是(*p),p[0]呢?还是其它什么,如果仔细思考一下,就会发现之前的这两种方式不可以了,因为现在这个存储空间中不止一个数据元素,可能有多个,通过上面这两种方式到底是获取谁的值呢。所以(1)我们要指明是获取谁(2)再获取这个“谁”的值。反过来在赋值的时候也是同样的,先指明是谁,在给这个“谁”赋值。
这里的指明是谁,这个“指明”用符号“->”表示
示例
图解
第十一行:
第十四—十八行:
完结(ง •_•)ง