C语言:从基础到精通指针

        本期博客,将开始带领大家学习C语言指针这一篇章,学习C语言的都应该清楚,指针在C语言语法中,占着绝大部分。C编程的方方面面都离不开指针。相信各位通过这篇博客的学习,将对C指针的理解与掌握不成问题。

        学完指针之后,可以去学习其相关应用:C语言:再探C语言指针-CSDN博客,若博客对大家的学习有所帮助,还请点赞与支持❤❤❤。

一、初始指针

1.内存与地址
  • CPU(中央处理器),需要向内存读取数据,处理完数据后,还需要将数据放回到内存中,那CPU是如何从内存找到他自己想要的数据呢?        
  • 现实中,我们去向宾馆申请一间房间,前台的服务人员,会给我们找出一间闲置的空间供给我们使用,并返回给我们一个房卡。那她是如何快速的找到一间闲置的空间呢?那是因为每一间闲置的空间都有编号。当我们不用的时候,她们就会收回这间屋子的使用权。
  • 我们将CPU抽象为前台服务人员,把内存抽象为宾馆的房子,把CPU读取数据抽象为去宾馆申请房子,把CPU返回数据抽象为收回这间屋子的使用权......
  • 我们就可以推断出,内存也被划分了很多个内存单元,每一个内存单元有自己的专属编码
  • 结论:内存被划分为很多个大小为一个字节的内存单元,每一个内存单元都有相对应的内存编码,内存编码又叫做地址。CPU处理数据的时候,则是根据地址去找到所需的数据。
2.指针变量与地址
  • 有时候,我们自己要处理数据的时候,也必不可少要用到地址,所以C语言允许我们获得变量的地址,并使用地址,或者通过地址找到该数据,进行使用。
  • C语言规定了一个指针变量,专门用来存储数据地址,并且有两个操作符(取地址操作符&,解引用操作符*)。
  • 下面是其简单的使用:
  • 结论:内存单元编码 == 地址 == 指针
3.指针类型的刨析
i.指针的理解 
  • (type) * p;

  • p     ->p是一个变量
  • *      ->变量p前面的(*),说明它是一个指针类型的变量
  • type->说明了指针变量p,所指向对象的类型
ii.指针在空间的大小
  • 了解过音乐的都知道,音乐有这几个音阶(do、re、mi、fa、sol、la、si),在钢琴制作的时候,也没有把哪个键标记下音阶,那演奏家是如何找到音阶的吗?那是因为音阶的分布是被死规定过的,且是公认的,无论哪几种钢琴,它的音阶所在按键位置是不变的。
  • 事实上,内存单元的编号也被按照某种标准的规定所设定,计算机中存在地址线,正电流表示二进制1,负电流表示二进制0;在32位平台上,由32根地址线的表示一个内存单元的地址,也就是一个整型,在64位平台上,由64根地址线的表示一个内存单元的地址,也就是两个整型。
  • (int)类型在内存中占据4个字节,但我们取它地址的时候,常用第一个内存单元的地址,作为该int类型的地址。
  • 小结:在32位平台上,地址由32比特位构成,也就是1个(int)类型的大小,4个字节;在64位平台上,地址由64位比特位构成,也就是2个(int)类型的大小,8个字节。无论什么类型的指针,只要是用来存放地址的,其指针类型的字节大小只与平台有关->(4/8)。

iii.指针类型有什么用? 

  • 这里我就不卖关系了,直接告诉你们结论:
  • 指针类型决定着,指针变量解引用后所能操作的空间
  • 指针类型决定着,指针变量+/-n个整数后,指针的地址变化的字节(为指针所指向对象的类型在内存空间占用字节大小的n倍)。
4.const修饰指针
  • 关键字const的作用:
  • 使变量,具有常量属性->其变量所存储的数据,不可被修改(但它仍算是变量,并非我们常说的常量) 
  • const在(*)的左边,const修饰的是指针变量所指向的对象不能够被修改。
  • const在(*)的右边,const修饰的是指针变量所存储的地址不能够被修改。
5.指针的运算
i.指针+/-整数
  • 指针 +/- 整数(n) = 指针当前的值 +/- n*(指针所指向对象的类型在内存中所占用的字节大小)
ii.指针-指针
  • 在我日常生活都会用到日期,月份 +/- 天数 = 月份;月份 - 月份 = 天数。
  • 如果我们把月份抽象为指针,把整数(n)抽象为天数。我们就能推测出指针 - 指针 = 此整数(n);n的意义是:两个指针之间元素的个数。
  • 注:两个指针必须指向同一块空间,比如一个一维数组,一个指针指向数组的首元素,另一个指针指向数组的末元素,结果就是数组的元素的个数。就好比农历的月份 - 阳历的月份没有意义。
iii.指针的关系运算
  • 指针的关系运算很好理解,就是指针之前可以进行(<,>,<=,<=)逻辑运算。毕竟地址是有高地址与低地址的,且地址是由32比特位或64比特位表示的。自然就能进行逻辑运算。
6.void* 类型的指针
  • (void*)类型的指针 :可接收任意类型的指针,但不可解引用,也不可进行指针的关系的运算。
  • void* 指针常用来做函数的参数或返回值,
  • 具体案例请看下面的冒泡排序的思想封装一个可以比较任意类型的一组数据的函数。
7.野指针

i.什么是野指针

  • 野指针就是一个指针变量指向的空间,或是随机值或已经被释放,总之就是未经操作系统允许的空间,好比你去宾馆开房,房子都回收了,你再去使用是不合法。

ii.野指针产生的情景

  • 指针未被初始化:
  • 了解过函数栈帧的都知道,局部变量未初始化,其指向的数据是0xcccccc,是随机值。因为VS检查太严格,无法有具体的代码案例。
  • 指针访问越界:
  • 指针指向了已被释放的空间:
8.如何避免野指针
  • 前面我们已经知道了指针越界的三种情况,我们在使用指针的时候如何避免野指针?
  • 指针变量要记得初始化。
  • 尽量避免使用指针越界的情况。
  • 将暂时用不到的指针变量赋值成空指针:NULL。NULL的值为0,内存中,并不是所有的内存是允许我们访问的,会有一部分内存空间留给操作系统。所以访问NULL会之间报错,你用都用不了。这样也能让我们就算有错,也能知道。
  • 检测是否为NULL:若能做到上面的操作,则我们使用的指针要么是NULL,要么就是合法的指针。所以在使用指针的使用用if语句作判断,若指针不为NULL,才使用。

二、常见指针类型

1.二级指针变量
  • 二级指针:
  • 接收一级指针的指针,(type*) *pp;
  • pp是一个变量
  • *与pp结合,表示pp是一个指针变量
  • (type*) 的类型说明,pp指向对象的类型
  • 常用场景在函数传参的时候,参数有一级指针,且一级指针需要被更改的时候,我们就需要传递一个二级指针。 
2.字符指针变量
  • 字符指针
  • char* p;
  • p是一个变量
  • *与p结合,表示p是一个指针变量
  • char说话,p指向的对象是char类型
3.指针数组
  • 指针数组:
  • 是一个数组,数组的元素是指针;(type*)arr[整型常量N]
  • arr先与 [] 结合,表明它是变量arr是数组名,其中整型常量N表示该数组含有N个元素
  • (type*)表示该数组每一个的元素的指针类型;
4.数组指针变量
  • 数组指针:
  • 是一个指针,指向的对象是一个数组;(type)(*p)[整型常量N]。
  • p先于(*)结合,表示它是一个指针,因为[]的结合性强于*,所有得用上()。
  • 数组的类型是 (type) [整型常量N];
5.函数指针变量
  • 函数指针:
  • 是一个指针,指向的对象是一个函数;(type) (*p) (type,type)
  • p先于(*)结合,表示它是一个指针,
  • 后与 () 结合,表面p指向的对象是一个函数。
  • 括号里的两个type,表明函数的参数的类型,前面的type,表示函数的返回类型。
  • 注:函数名与&函数名,所代表的含义一致
6.函数指针数组
  • 函数指针数组:
  • 是一个数组,数组的元素的指针,但这里有的特殊,数组的元素是函数指针;
  • 带你们分析理解了那么多个类型,这个自主分析
  • 代码案例,转移表;下面讲的有。
7.typedef关键字
  • 关键字typedef:   
  • 将一个数据类型重定义,使复杂的类型,可以简单化;
  • typedef type NEW_type
  • 将类型为type的,重定义为NEW_type,
  • 我们可以用type类型创建一个变量,也可以用NEW_type;
  • 注:NEW_type与type是完全等价的,与#define宏定义的符合替换不同

三、深入理解指针

1.一维数组:数组名的理解
  • 数组名:
  • 一般情况数组首元素的地址
  • 除了关键字sizeof后面的数组名,与&数组名
2.二维数组:数组名的理解
  • 数组名:
  • 一般情况数组首元素的地址
  • 除了关键字sizeof后面的数组名,与&数组名
  • 二维数组的元素是?
  • 二维数组是将每一组一维数组当作它的元素。
  • 所以数组的首元素的地址是第一行数组的地址,
3.一维数组传参
4.二维数组传参
5.指针数组模拟二维数组
i.模拟思路
ii.代码实现

6.二级指针模拟二维数组
i.模拟思路

 注:int*类型的元素,是连续的,常用的情景是动态开辟空间模拟二维数组。

ii.代码实现

  • 61
    点赞
  • 31
    收藏
    觉得还不错? 一键收藏
  • 18
    评论
评论 18
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值