目录
续上篇
4、数组参数、指针参数传参
在写代码的时候难免把【数组】或者【指针】传给函数,那函数的参数如何设计呢?
4.1一维数组传参
对于arr1和arr2来说,这五种形式的传参都是合理的。
4.2二维数组传参
上面的例子说明,二维数组传参,函数的形参只能省略第一个,因为对于一个二维数组,可以不知道有多少行,但是必须知道每一行有多少个元素,这样才能对数据进行分配。
现在我们用指针进行传参:
只有第三种指针(数组指针)传参是可行的。
4.3 一级指针传参
如此一个函数,实现对数组的打印,实参部分传递指向数组首元素地址的指针p,以及记录数组大小的sz。形参接收用一个一维指针和一个整型变量接收。
(思考:如果函数的形参是一维指针,那实参可以传什么呢?答案:整型变量的地址&a;指针*p;数组名.....)
4.4 二级指针传参
对于二级指针传参,需要用二级指针接收,或者对于&指针传参,接收也是需要二级指针的。
(思考:如果函数的形式参数是二级指针,调用该函数时,可以传什么类型的变量过去?答案是:二级指针;&数组名;&指针;指针数组.....)
5、函数指针
数组指针:指向数组的指针就是数组指针
函数指针:指向函数的指针就是函数指针
函数也有地址码?先看一段代码:
的确,函数也是有地址的。所以我们可以用一个指针去指向函数,这样的指针就是函数指针。对于函数来说,取地址函数名和函数名都是函数的地址。
那么我们怎么去创建指针,去存放函数的地址呢?创建好之后又如何使用呢?
看到这个代码,我们知道,函数指针的创建其实跟数组指针又异曲同工之妙,使用时只需要调用指针解引用并将要传的参数写入,就能得到函数运行后的返回值。在前期,这样的指针看上去没有很大用处,但是到了之后写一些较为复杂的代码时,函数指针的作用就会体现出来。
简单讲一个用法:当我们想引用一个函数,传参为另外一个函数时,这时的形参就只能用函数指针接收。所以,函数指针的出现,让我们能够将函数作为参数传给另外一个函数,为代码提供了新的可能。
6、函数指针数组
数组是一个存放同类型数据的存储空间,那么函数指针数组就好理解了,函数指针数组就是一个存放类型都为函数指针的数组。
上面这个例子,arr就是一个函数指针数组,它存放了四个函数指针,这四个函数指针分别指向函数:Add、Sub、Mul、Div。由于这四个函数的函数返回值,函数参数都是同类型的,所以可以放在一个数组中。
如何通过函数指针数组调用函数指针:
arr[0]其实就是指向Add的函数指针,实现的是加法运算,发现结果如预期,所以调用成功。
如此就可以调用函数指针数组中的函数指针,注意,这里我和前面调用函数指针不一样,我没有加*,也就是( (*arr[0])(1 , 2) ),加上这个*和不加都可以去调用函数指针所指向的函数,加上*是方便理解一点,不加其实也没问题,这是函数指针数组的独特特性,其他指针访问时一定要加上*。
函数指针数组的运用,要配合函数指针,在以后实现复杂功能的程序编写时,运用函数指针数组,可以极大地简化程序地修改和优化成本。
7、指向函数指针数组的指针
指向函数指针数组的指针,其实还是一个指针,只不过其内容是函数指针数组的首地址,指向函数指针数组。
如何定义,如何运用:
可以看到,只需要在定义函数指针数组的形式的基础上,再加一个*去声明指针pfarr即可,在运用时,用*进行解引用之后就跟函数指针数组的用法相同,可以看到,上面也例子也是成果调用了arr数组中第一个指针所指向的函数Add的功能。
对于函数指针数组的指针,运用情况较少,但也是有运用的可能的,所以可以大概了解一下。
接下来,我们要将一个很重要的知识了:回调函数。
8、回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方法直接调用,而是在特定事件或条件发生时由另外的一方调用,用于对该事件或条件进行影响。(就是我在说函数指针的作用时提到过的)
如此,就是回调函数的简单流程。在函数B中,有一个参数是指向A的函数指针,在函数B中可以通过PA函数指针去调用函数A。
举例:qsort函数
对于qsort函数,它可以比较任意数据的大小并排序,我们观察它的形参(上图),发现其中有一个函数指针类型:int(*cmp)(const void* e1,const void* e2)。
这其实就是一种函数回调,qsort函数内调用了另一个函数cmp,根据数据的大小(单位字节)来对应地调用cmp这个函数。
实现了排序。
总结
本篇文章按顺序讲解了数组、指针传参;函数指针;函数指针数组;指向函数指针数组的指针;回调函数。是c语言进阶的指针篇。