C语言指针拾遗

指针这种东西,是需要记录下来才能理解的比较清晰,所以专门记录一下指针的一些知识点:

  1. 指针理解
    1. 指针也是一种数据类型,和其他各种数据类型基本一样
    2. 指针有几个要素
      1. 指针的的值,就是该指针变量的值,该值就是一个内存地址的编号,这个内存地址就是该指针所指向的变量所处的内存地址
      2. 指针变量的变量名,该变量名和其他各种数据类型的变量名没有任何区别,都是一个变量名而已
      3. 指针可以指向任何数据类型,通过指针的值,从而找到对应数据类型的值
    3. 由于存储的是内存地址,所有的指针变量的取值范围都是固定的,不会超出内存空间的长度大小
    4. 指针变量自身也存在于内存中,所以指针变量也有内存地址,因此别的指针变量也可以指针向这个指针变量,这样就构成了多级指针,例如int *a = &x,而int *b = &a,则a就是单级指针变量,b就是多级指针变量
    5. 指针本质要做的就是通过内存地址来间接访问变量值,增加了一种访问变量值的方法,由于引入了内存地址的概念,使得C可以操作内存中的数据
    6. 要在printf中打印指针变量的值,用%p做占位符
  2. *号的应用
    1. *号在数据类型和变量名之前的时候,表示定义一个指针变量,*后的变量名就是该指针变量的名字
    2. *号单独位于指针变量之前,表示取出该指针变量所指向的变量的值
    3. 指针变量有几级,取出最终原始变量的值就需要使用几个*
  3. &号的应用
    1. &号位于变量之前,表示取该变量的内存地址
  4. 指针与数组
    1. 首先要明白概念,数组的内存地址就是数组的首元素的内存地址
    2. 数组名有多重作用:
      1. 首先,数组名是整个数组的代表,通过数组名[i]可以依次访问数组中的每个元素
      2. 其次,数组名的值就是整个数组的内存地址,里边存放的就是数组的内存地址,所以数组名可以直接赋值给指针变量,且不需要取地址符&,例如:int a[3]; int *b = a;,可见数组名可以完全看作一个指针变量,
      3. 再次,由于数组的内存地址就是数组首元素的内存地址,所以数组名的值就是数组首元素的内存地址,则可以得出如果int a[3];则a的值等于&a[0], 那么&a[0]则可以直接赋值给指针变量,可以得出int a[3]; int *b = &a[0];,和上边赋值的效果是一样的
    3. 使用指针操作数组,实际上是操作的数据的内存地址
    4. 假设有int a[3]; int *b = a;,则可以使用指针变量b来获取数组中的每一个元素的值,操作方式是*(b + i),由于b的值就是首元素的地址,那么获取首元素的值可以直接使用*b就可以拿到,
  5. 指针的运算
    1. 指针可以进行加减乘除运算,乘除运算一般在指针上没有意义,所以通常指针都进行的是加减运算
    2. 指针的加减运算单位不是以内存基本单元byte为单位的,而是以指针所指向的数据类型所占的内存大小为单位的
    3. 参照这个公式:假设有int a[3]; int *p = a;,则指针运算”p + n”等同于p的值加上sizeof(int) * n个byte,最中的结果将会停留在第n个元素的内存地址处,例如数组的内存地址为0x00001,则p初始化后值也为0x00001,则运算”p + 2”的结果等于0x00001 + (sizeof(int) = 4) * 2 = 0x0009,而0x0009就是第三个元素的内存地址
    4. 通常情况下在数组中会使用指针运算,但是不排除也会在其他数据类型中使用指针运算。例如结构体
    5. 指针运算本质上也是变量的运算,所以当然也可以使用++,–等运算符
      1. 指针++与–运算符的结果与+1和-1的结果一样
      2. 原则上,由于++,–运算符的优先级与的优先级一样,那么在进行*p++这种运算的时候,就要看两个运算符的结合方式了,最终得出先算++后算的顺序,那么可以省略了p++两边的括号,可见这种运算方式比较简洁,并且可以得出公式:”p++” = “*(p++)” = “(p+1)”
      3. 可是实际情况不如我们所料,实际情况中p++并没有得到下一个数组元素的值,原因是因为p++是后置++,有先运算后++的特性,则我们的*p++的执行顺序变成了先算号后算++,所以得到的结果还是当前指针指向的结果
      4. 如何修复呢?
        1. 可以在p++外面加上括号,提高该部分的优先级,则会是这样:*(p++)
        2. 可以把++前置,组成先++后运算的顺序,则会是这样:*++p
      5. 可以得出:
        1. *p++会直接得到当前元素的值,直到运算完毕之后,才会将p进行++,可以得出公式:”*p++” = “(*p)++”,这一点在参与运算的时候要注意
        2. *(p++)会得出下一个元素的值,可以得出公式:”*(p++)” = “*++p” = “a[n+1]”
      6. –运算符与++运算符思路一样
  6. 函数的指针参数
    1. 函数列表中的参数类型可以是指针类型,例如:int add(int *a,int *b),这里的形参格式与定义指针变量的格式是一样的
    2. 参数被定义为指针的函数,实参必须是一个指针变量,假设int *a = &x;int *b = &y;则1中的函数需要这样调用:add(a,b);
    3. 由于基本数据类型的函数参数是传值调用,所以2中的函数调用过程中,指针变量a,b的值将会被拷贝一份传递给形参,而a,b的值不会受到任何影响,
    4. 由3可知,形参就是一个指针变量,形参的值其实是一个内存地址,那么在函数中,我们就可以随意操纵指针所指向的变量的值,由于我们操纵的是内存中指针,所以内存中的数据是会确切的发生改变的
    5. 例如swap函数,形参得到的实参的拷贝,获取到内存地址之后进行运算,最终会将实参所指向的变量的值进行改变,而实参自身却没有发生任何变化
    6. 通过这样的运算可以得出,类似于*p这样的取值运算,操作的是指针变量的值所指向的那个变量,而跟指针变量名无关,例如两个变量名不同的指针变量p1和p2,有着相同的值,那么通过*p = 123;这样的运算之后,p2指针所指向的变量的值也会被修改为123,由此可见操作内存地址的重要性
  7. 指针与const
    1. const在*p之前,表示p的值可以变化,但是p指向的是一个常量,它的值不能改变
    2. const在*和p之间,表示p是一个常量指针,p里边的值不能变化,但是p所指向的变量的值可以发生改变
    3. 如果1和2都符合,则表示一个常量指针指向一个常量
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值