• 理解C语言指针


    指针

    理解指针

    指针在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)再获取这个“谁”的值。反过来在赋值的时候也是同样的,先指明是谁,在给这个“谁”赋值。

           这里的指明是谁,这个“指明”用符号“->”表示

    示例
    在这里插入图片描述
    在这里插入图片描述

    图解
    第十一行:
    在这里插入图片描述

    第十四—十八行:
    在这里插入图片描述

    完结(ง •_•)ง

  • 相关阅读:
    SeamlessM4T—Massively Multilingual & Multimodal Machine Translation
    Oracle SQL执行计划操作(2)——索引相关操作
    登录功能和退出功能(瑞吉外卖)
    云原生数据湖应用洞察白皮书
    坚持做一件事情
    【Flink】一文解析Flink如何实现状态管理和容错机制
    第6章 集成第3方依赖注入中间件“Autofac”
    hadoop集群搭建
    统计十进制数的二进制表示中1的个数 ← 清华 邓俊辉
    Shell之wc命令
  • 原文地址:https://blog.csdn.net/baiqi123456/article/details/126231203