c语言之指针进阶(一)

目录

0.前言

1.字符指针

2.指针数组

3.数组指针

3.1数组指针的定义

3.2数组名和&数组名的区别

3.3数组指针的使用

4.函数指针

5.函数指针数组

6.指向函数指针数组的指针

7.回调函数


0.前言

在讨论指针进阶之前,我先帮大家梳理一下指针的知识:

1. 指针就是个变量,用来存放地址,地址唯一标识一块内存空间。

2. 指针的大小是固定的4/8个字节(32位平台/64位平台)。

3. 指针是有类型,指针的类型决定了指针的+-整数的步长,指针解引用操作的时候的权限。

4. 指针的运算。

接下来,我要跟大家讨论指针更高级的用法。

1.字符指针

在指针的类型中我们知道有一种指针类型为字符指针char*;

一般如下使用:

这里,我们可以看到我首先定义一个char类型的变量ch,然后通过字符指针指向ch的地址,在解引用修改ch的值。

它其实还有一种使用方法,如下:

这里呢,特别让人以为是把字符串“hello bit”放到字符指针pstr里了,但其实本质是将字符串“hello bit”中的首字符的地址放在了pstr中。也就是说这段代码的意思是把一个常量字符串的首字符h的地址存放到字符指针变量pstr中。

那就可以有下面这道有趣的题:

 这里的结果是什么呢,大家可以先思考一下,再看我的解析,

 这里str3和str4指向的是一个同一个常量字符串。C/C++会把常量字符串存储到单独的一个内存区域,当几个指针 指向同一个字符串的时候,他们实际会指向同一块内存。但是用相同的常量字符串去初始化不同的数组的时候就会 开辟出不同的内存块。所以str1和str2不同,str3和str4相同。

2.指针数组

这里呢,我给大家类比分析一下,首先我们说什么是整形数组呢,是存放一堆整形的数组,所以同理指针数组就是存放一堆指针的数组。一定要注意数组里存放的是一群相同的元素,不要里面的元素变复杂了就开始犯迷糊。接下来我给大家看几种指针数组类型:

int* arr1[10]; //整形指针的数组
char* arr2[4]; //一级字符指针的数组
char** arr3[5];//二级字符指针的数组

3.数组指针

3.1数组指针的定义

数组指针是数组还是指针?

答案是指针,如果你要是分辨不清的话可以在最后两个字的前面加上一个的字,因为的前面的内容是修饰的后面的内容的,这样我觉得就很好分辨了。

我们已经熟悉:

整形指针:int* p;能够指向整形数据的指针;

浮点型指针:float* pf;能够指向浮点型数据的指针;

那么数组指针就应该是能够指向数组的指针;

那么数组指针长什么样子呢,让我们看下面两个代码:

int *p1[10];

int (*p2)[10];

//p1, p2分别是什么?

这时,已经有聪明的小伙伴猜出来了,没错,p1为指针数组,p2为数组指针,那么他们两个有什么区别呢,让我来给你们解释,这里呢我就先来解释p2吧,首先p2先和*结合,说明p2是一个指针变量,然后指向的是一个大小为10个整型的数组。所以p2是一个指针,指 向一个数组,叫数组指针。 这里要注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合。而p1由于没有括号,所以先跟[]结合,所以p1是指针数组。

3.2数组名和&数组名的区别

对于下面的数组,arr和&arr有怎样的区别:

int arr [10] ;

我们都知道arr是数组名,表示数组首元素的地址,那么&arr呢,让我们来看一段代码和运行结果:

那么,为什么它们两个的地址是一样的呢,难道它们两个是等效的吗,别急,再来看接下来的代码和运行结果:

 根据上面的代码我们可以发现,其实&arr和arr,虽然值是一样的,但是意义是不一样的。 实际上: &arr 表示的是数组的地址,而不是数组首元素的地址。 本例中 &arr 的类型是: int(*)[10] ,是一种数组指针类型 ,而arr的类型是:int*,所以arr+1代表跳过一个整形,也就是4个字节,而&arr+1代表跳过整个数组,而这个数组有10个元素,每个元素类型都是整形,所以跳过了4*10=40个字节。

3.3数组指针的使用

既然数组指针指向的是数组,那数组指针中存放的应该是数组的地址。看代码:

 接下来,给大家一个数组指针的应用:

 看到这里应该就有人问了,不是用的指针吗,为什么最后还是用的数组访问下标,其实用这个是方便理解,用指针也是可以的,那我就以二维数组为例了,看代码和运行结果:

 这里p为数组名,又因为二维数组可以称为装有一维数组的数组,所以对p解引用,p为首元素的地址,所以这里p为第一行一维数组的地址,在通过变量i的变化实现行的变换,然后在解引用可以得到一维数组的首元素地址,通过j变量可以实现列的变换,然后在解引用得到地址里的元素。

4.函数指针

什么是函数指针,参考数组指针,我们可以得出能够指向函数的指针我们叫它函数指针,举个例子:

这是一个非常简单的函数指针,这里我是写了一个简单的加法实现函数,然后通过函数指针指向函数的地址,这里如果我们正常去用这个函数的话,应该是这样去用的Add(2,3),其实这个就是通过函数名找到这个函数地址从而进行调用,而这里我定义了一个函数指针,而这个函数指针的类型是跟函数一一匹配的 ;比如我写的这个函数指针的类型为int(*)(int,int),前面的int为函数的返回类型,后面括号里的为函数的参数类型,*代表是指针。而我在打印的时候为什么用p可以直接打印,就是因为p是指向函数的地址的,所以通过p可以直接访问函数,这个你把p解引用也是可以的。

5.函数指针数组

是不是有点蒙了,其实它的最后两个字很关键,数组,没错它是数组,要把函数的地址存到一个数组中,那这个数组就叫函数指针数组 ,例如int (*p[4])(int,int)就是函数指针数组,数组的内容是什么呢?是int(*)(int,int)类型的函数指针,那接下来就上一个实例来帮助大家理解,就接着上面那个函数说,如我我想实现基本计算器的功能,就是加减乘除,又该怎么办呢?

这里我先拿最普通的方法来解:

 这里呢就是实现基本计算器一个常规的解法,但是大家有没有发现有很多的重复代码,这显得整个程序的实现非常的冗余,那么有没有什么办法可以解决呢,当然有而且还不止一种方法,当然这里我就先给出一种用函数指针数组的做法,还有一种回调函数的做法我接下来会讲到,别着急。那么,用函数指针怎么做呢 ,看代码:

是不是简化了很多,建立一个函数指针数组,里面存放的是函数指针,在通过变量input访问数组下标来找到相应的函数,实现相应的功能,这里注意我们想要输入1的时候实现add函数,而把函数放在数组里第一个的下标为0,所以这个我放了一个空指针进去顶了一位,目的就是让函数与变量一一对应。

6.指向函数指针数组的指针

指向函数指针数组的指针是一个 指针 指针指向一个 数组 ,数组的元素都是 函数指针 ;

如何定义?

 因为这个东西没有前面的重要和实用,我就不过多叙述了,大家看看就好了,就是套娃。

7.回调函数

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当 这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调 用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

这里我讲解一下怎么用回调函数实现基本计算器,代码如下:

 这里呢,add,sub,mul,div都作为参数,有需要的时候才会回调给calc函数,而calc函数也用函数指针来接收。

然后我们来演示一下qsort函数的使用:

这里需要注意qsort的第四个参数需要使用者根据自己的需要自己写一个函数,其实这个函数就是回调函数。

 接下来使用回调函数,模拟实现qsort函数。

如下:

这里呢我先说参数,第一个参数为起始位置,为什么用void*,是因为这个函数不是单一的为一种类型数据排序的,所以不知道使用者会用哪种数据类型排序,而void*可以接收任意类型的数据,第二个参数为元素个数,第三个参数为每个元素所占的字节数,第四个参数是一个指向使用者写出的回调函数的指针。排序采用冒泡排序没什么好说的,而交换函数参数类型为什么是char*,是因为char*每次只会跳过一个字节,而j*size则是从开始到你想要交换的数字的地址间空了多少字节,从而实现交换逻辑。

好了,我今天就分享到这里,由于这次博客较长,可能会出现错字以及错误,所以up文章哪里有不妥之处还望见谅,如果对你有帮助的话就请给up博文一个赞吧,多谢大家!!!

  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 13
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值