1.指针数组的引入
1、指针数组的概念:指针数组本身是一个数组,是若干个相同类型的指针变量顺序存储构成的集合。因此,定义指针数组的目的就是为了存放多个地址编号。举个简单的例子:
2、指针数组的类型:数组有三要素,但数组并不关心它的第一维长度,它关心从第二维开始的长度以及数组元素的类型,一般来说,指针数组都是一维的,所以我们仅仅关注数组元素的类型就行了,对于指针数组来说,我们格外关注指针数组里到底存放的是什么类型的指针(普通指针、数组指针、还是函数指针)。
3、指针数组定义时关心什么?:
- 指针数组是一个数组,所以先将arr与中括号结合,表明arr是一个数组;其次关心数组中的元素类型,也就是判断指针数组里到底存放的是什么类型的指针(普通指针、数组指针、还是函数指针),最后关心数组的元素个数。
- 适用于变量、指针、函数的类型判别方法:
- 找到变量名,若没有变量名,找到最里面的结构
- 向右看,读出看到的东西,不要跳过括号
- 向左看,读出看到的东西,不要跳过括号
- 若有括号,跳出第一层括号
- 重复上述过程,直到读出最终的类型
4、普通指针数组的定义、初始化、引用:看起来没啥用,我们做个简单练习
-
代码心得1:通过数组下标方法访问到的是普通指针变量,所以还需要用*运算符来取内容;尽管 [ ]运算符的优先级高于*运算符,但是实际引用指针数组元素时,尽量加小括号,否则可能被批斗。
- 代码心得2:既然定义时*修饰符不与数组名arr结合,那么我们就不要把*和arr挨着写,让*和类型挨着写。
- 举例:
#include <stdio.h> int main(int argc, char const *argv[]) { int a=10, b=20, c=30, d=40; int* arr[4] = {&a, &b, &c, &d}; //普通指针数组,数组有4个元素,存放的是int*类型的指针 for(int i=0; i<4; i++){ printf("%d ", *(arr[i])); //数组下标法使用,也可以写成:*arr[i] } return 0; }
2.实战——函数指针数组
1、函数指针数组的概念:函数指针数组本身是一个数组,是若干个相同类型的函数指针变量顺序存储构成的集合。
v
2、如何定义一个函数指针数组:
- 找到多个具有相同返回值类型、相同形参列表类型的函数:也就是我们数组保存的对象,确定它们的个数
int getMax(int data1, int data2); int getMin(int data1, int data2); int getSum(int data1, int data2);
- 标准的写法:
int (*pfunc[3])(int data1, int data2); //函数指针数组
3、函数指针数组为啥这样写?(通用的类型判别方法):
- 函数指针数组是一个数组,根据优先级,[ ] 高于 *,所以先将pfunc与中括号结合,表明pfunc是一个数组;再和*结合,表示数组fpunc[3]里的元素是指针;然后根据优先级,*func[3]再和(int data1, int data2)结合,表明数组元素里的指针指向函数,最后和int结合,表示函数的返回值是int类型的。
- 适用于变量、指针、函数的类型判别方法:地位从高到底
- 找到变量名,若没有变量名,找到最里面的结构
- 向右看,读出看到的东西,不要跳过括号
- 向左看,读出看到的东西,不要跳过括号
- 若有括号,跳出第一层括号
- 重复上述过程,直到读出最终的类型
4、初始化函数指针数组:注意数组如果不初始化,数组里面的指针就是野指针。
int getMax(int data1, int data2);
int getMin(int data1, int data2);
int getSum(int data1, int data2);
int (*pfun[3])(int data1, int data2)={
getMax,
getMin,
getSum}; //函数指针数组定义和初始化
习题1:【遍历函数指针数组,实现函数间接调用】有两个操作数a和b,输出它们的最大值、最小值、和。
- 思路:
f1. 封装求最大值的API:int getMax(int data1, int data2); f1.1 用三目运算符返回最大值 f2. 封装求最小值的API:int getMin(int data1, int data2); f2.1 用三目运算符返回最小值 f3. 封装求和的API:int getSum(int data1, int data2); f3.1 返回两数之和 1. 定义并初始化两个数a和b 2. 定义一个同时保存API1. API2. API3. 这三个函数地址的函数指针数组,并初始化: int (*pfuncArr[3])(int data1, int data2)={ getMax, getMin, getSum}; 3. for循环,代表函数指针数组下标的循环变量i从0开始,<3 时,进入循环 3.1 遍历函数指针数组,实现函数间接调用,将结果保存在ret变量中 3.2 打印ret变量
- 代码:
#include <stdio.h> int getMax(int data1, int data2); int getMin(int data1, int data2); int getSum(int data1, int data2); int main(int argc, char const *argv[]) { int a=10, b=20; int ret; int (*pfuncArr[3])(int data1, int data2)={ getMax, getMin, getSum}; //函数指针数组定义和初始化 for(int i=0; i<3; i++){ ret = (*pfuncArr[i])(a,b); //遍历函数指针数组,实现函数间接调用 printf("%d ", ret); } return 0; } int getMax(int data1, int data2) { return data1>data2 ? data1 : data2; } int getMin(int data1, int data2) { return data1<data2 ? data1 : data2; } int getSum(int data1, int data2) { return data1+data2; }
习题2:【函数指针数组作为函数的形参】用函数指针数组实现决策函数Handler调用多个API的功能:
- 知识点:【如何定义一个指针指向函数指针数组?】 从里往外读 ,遵循通用的类型判别方法
- 思路:
f1. 封装求最大值的API:int getMax(int data1, int data2); f1.1 用三目运算符返回最大值 f2. 封装求最小值的API:int getMin(int data1, int data2); f2.1 用三目运算符返回最小值 f3. 封装求和的API:int getSum(int data1, int data2); f3.1 返回两数之和 Handler1. 封装数据处理的API:int dataHandler(int data1, int data2, int cmd, int (*(*ppfuncArr)[3])(int data1, int data2)); //形参中data1和data2是操作数,cmd是操作指令,int (*(*)[])(int, int) 是函数指针数组的地址,用于接收函数指针数组的数组名 Handler1.1 定义一个函数指针fpunc一会儿用于调用: int (*pfunc)(int data1, int data2); Handler1.2 switch选择语句,表达式是cmd。目标是从数组pfuncArr中确定pfunc的指向 Handler1.2.1 case 1: 让函数指针pfunc指向API1.的地址: pfunc = (*ppfuncArr)[0]; break; Handler1.2.2 case 2: 让函数指针pfunc指向API2.的地址: pfunc = (*ppfuncArr)[1]; break; Handler1.2.3 case 3: 让函数指针pfunc指向API3.的地址: pfunc = (*ppfuncArr)[2]; break; Handler1.2.4 default: 输入无效数字,用exit(-1);提前结束整个程序 1. 定义并初始化两个数a和b 2. 定义一个同时保存API1. API2. API3. 这三个函数地址的函数指针数组,并初始化: int (*pfuncArr[3])(int data1, int data2)={ getMax, getMin, getSum}; 3. 输入1或2或3保存在cmd中 5. 调用Handler1. 将操作数a和b,操作指令cmd,以及函数指针数组pfuncArr传递进去,返回值保存在结果ret中: ret = dataHandler(a,b,cmd,pfuncArr); 6. 打印结果ret
- 代码:
#include <stdio.h> #include <stdlib.h> int getMax(int data1, int data2); int getMin(int data1, int data2); int getSum(int data1, int data2); int dataHandler(int data1, int data2, int cmd, int (*(*ppfuncArr)[3])(int data1, int data2)); int main(int argc, char const *argv[]) { int a = 10; int b = 20; int ret; int cmd; int (*pfuncArr[3])(int data1, int data2)={ getMax, getMin, getSum }; puts("请输入1(取大值),2(取小值),3(求和)"); scanf("%d", &cmd); ret = dataHandler(a, b, cmd, pfuncArr); printf("%d\n", ret); return 0; } int getMax(int data1, int data2) { return data1>data2 ? data1 : data2; } int getMin(int data1, int data2) { return data1<data2 ? data1 : data2; } int getSum(int data1, int data2) { return data1+data2; } int dataHandler(int data1, int data2, int cmd, int (*(*ppfuncArr)[3])(int data1, int data2)) { int ret; int (*pfunc)(int data1, int data2); switch(cmd){ case 1: pfunc = (*ppfuncArr)[0]; break; case 2: pfunc = (*ppfuncArr)[1]; break; case 3: pfunc = (*ppfuncArr)[2]; break; default: puts("请重新输入"); exit(-1); } ret = (*pfunc)(data1, data2); return ret; }