C语言概括(指针)

C语言概括(指针)

一. 指针的概念

(1) 通俗的讲就是把内存想象成一个大走廊,走廊上有很多房间,每个房间的大小都是1个字节,每个房间上面都带有一个门牌号,从0开始,依次递增,这个房间号,就叫"地址",就可以使用另外一块内存空间来保存这个地址,那么这样的内存空间就称为"指针变量".
(2)概念:指针是一个变量,变量里面存了一个整数,这个整数具有特定的含义就是表示内存中的地址.
(3)指针变量涉及两方面的信息

  1. 这个地址从哪开始
  2. 这个地址有多长(这个体现在类型里,short对应的内存是2个字节;int对应的内存空间是4个字节)
    注:两方面信息综合才能确定一个内存空间
    (4)指针变量的长度:指针变量的长度是固定的,在32位Windows下,固定是4个字节,在64位Windows下,是8个字节;
    (5)野指针:
    如果给指针随便赋值一个整数,此时大概率是无效的地址,如果一个指针里面存的是一个无效的地址的话,此时就称这个指针是"野指针";对于野指针解引用会导致未定义行为.
    (6)空指针(NULL):
    0X0这个地址比较特殊,对于我们的代码中是一定无法使用这个内存的,就可以认为0X0是野指针的一个典型代表,就管他叫"空指针(NULL)",他实际是一个宏,本质上是一个0的整数.对于空指针解引用会导致未定义行为.
二.指针运算(弊大于利)

(1)&运算
&运算,其实获取到的地址,是数值最小的这个地址
(2)*运算(解引用操作/间接访问/提领操作)

  1. 通过变量名获取变量内容,这样比较"直接",而"间接访问"是通过指针变量,先获取到地址,再根据地址找到对应的变量内容,这就没那么直接,这就叫做"间接访问";
  2. 解引用操作,重要的注意事项:
    必须针对有效的内存进行解引用,一旦解引用了无效内存,就会发生未定义行为(你申请到的内存,就是有效的内存,你没申请就是无效的内存,创建变量就是申请内存);eg:野指针和空指针都不能解引用
  3. 指针类型其实就是在描述针对指针解引用之后,得到的类型是什么
  4. 解引用时需要先找到对应的内存的起始地址,然后再获取到该内存长度,两者都得到了,才能真正读取这个内存的数据
    (3)指针加减整数
  5. 指针+1并不是单纯的地址+1,而是地址要加上一个值,使这个指针能够指向下一个元素;指针-1也是同样的道理.
  6. 指针加减整数的用途: 用来操纵数组;
    (4)指针减指针
  7. 大部分指针减指针都是无意义的,除非是两个指针指向同一个连续的内存空间(数组),此时指针相减才是有意义的.此时结果就表示两个指针中间隔了多少个元素(和指针类型密切相关),如果是两个不同类型的指针相减,编译器不会报错,但是结果无意义;
  8. 指针相减相当于是指针加减整数的逆运算.
    (5)指针比较大小
  9. 对于==和!=来说,这个比较普适的,任意两个指针都可以进行这样的比较(主要用于跟空指针比较).
  10. 对于< >,<=,>=来说,这样的比较是需要前提条件的,两个指针要指向同一个连续的内存空间,本质就是在比较指针变量里面储存的地址的值的大小关系.
    注: 比较< >这些比较少见,主要就是操作数组的时候或用到,而==和!=是非常常见的.
    (6)指针[ ]运算
    相当于是指针加减整数并且解引用的的简化写法
    eg: p[i]等价于*p(p+i)
    注:[ ]里面可以写负数,就相当于是指针的减法在解引用.
三. 特殊的指针void*

(1)概念:在c语言中有一种特殊的指针,只涉及到地址,不涉及大小,他就是void*,他并不是空指针,NULL才是空指针
(2)void的用处:假设我们需要写一个函数,这个函数需要同时兼容多种不同的的指针的时候,这个时候就可以使用void来解决了.因为不同类型的指针差别就在于"内存的长度",使用void就是暂时忽略了内存的长度.
(3)void
不能解引用;void不能加减整数;void之间也不能相加减.
(4) 使用void的弊端:c语言不支持泛型编程,所以使用void只是一种比较粗糙的模拟实现泛型的方案,这个方案存在诸多弊端
(5)可以把各种不同类型的指针和void*之间进行相互赋值.

四.数组和指针

(1) 数组名在有些时候能隐式转换成首元素的地址
(2)什么时候能隐式转换

  1. 函数传参
  2. 参与运算
    注:有些操作数组不支持,但指针支持,进行这样的运算,就会触发隐式类型转换:+ - 整数,==,!=,<,<=,>,>=,*这些都能触发.
    数组和指针本来是完全不相干的事情,只不过c语言中有惊天BUG,导致指针和数组混了;
    c中的数组一言不合就隐式转成指针;
    c中的指针又能[ ]搞的跟数组似的;
    (但要注意如果让说数组和指针有什么区别的时候,这句话本身就是错的,因为数组和指针本来就是完全不相干的事情,何谈什么区别)
    (3)指针数组和数组指针
  3. 数组指针:int(*)[4] (本体是一个指针)这是一个指针,指向了一个长度为4的int数组
  4. 指针数组:intarr[4] (本体是一个数组)这是一个长度为4的数组,每个元素是一个int
五.二级指针

(1)本质上就是一级指针,只不过指向的元素又是一个一级指针
在这里插入图片描述
p2就是二级指针,针对p2解引用得到的就是一级指针的值(int类型的)也就是p内部储存的值.
(2)一维数组进行函数传参的时候,就会隐式转换成指向首元素的指针(int[ ] => int
)
二维数组,进行函数传参的时候,也要隐式转成指向首元素的指针;例: int[3][4]得到的指针是一个指向长度为4的一维数组的指针int(*)[4]

六.const和指针

(1) const是一个关键字,用来定义一个常量
(2)const int* p = &a/int const * p = &a(p是不能被修改的)
在这里插入图片描述
(3)int
const p = &a (p的本身的值不能被修改)
在这里插入图片描述
(4)const int* const p = &a(都不能被修改)
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值