C的实用笔记30——指针数组(函数指针数组)

1.指针数组的引入

1、指针数组的概念:指针数组本身是一个数组,是若干个相同类型的指针变量顺序存储构成的集合。因此,定义指针数组的目的就是为了存放多个地址编号。举个简单的例子:

                                             

 2、指针数组的类型:数组有三要素,但数组并不关心它的第一维长度,它关心从第二维开始的长度以及数组元素的类型,一般来说,指针数组都是一维的,所以我们仅仅关注数组元素的类型就行了,对于指针数组来说,我们格外关注指针数组里到底存放的是什么类型的指针(普通指针、数组指针、还是函数指针)。

3、指针数组定义时关心什么?:

  1. 指针数组是一个数组,所以先将arr与中括号结合,表明arr是一个数组;其次关心数组中的元素类型,也就是判断指针数组里到底存放的是什么类型的指针(普通指针、数组指针、还是函数指针),最后关心数组的元素个数。
  2. 适用于变量、指针、函数的类型判别方法:
    1. 找到变量名,若没有变量名,找到最里面的结构
    2. 向右看,读出看到的东西,不要跳过括号
    3. 向左看,读出看到的东西,不要跳过括号
    4. 若有括号,跳出第一层括号
    5. 重复上述过程,直到读出最终的类型

4、普通指针数组的定义、初始化、引用:看起来没啥用,我们做个简单练习

  1. 代码心得1:通过数组下标方法访问到的是普通指针变量,所以还需要用*运算符来取内容;尽管 [ ]运算符的优先级高于*运算符,但是实际引用指针数组元素时,尽量加小括号,否则可能被批斗。

  2. 代码心得2:既然定义时*修饰符不与数组名arr结合,那么我们就不要把*和arr挨着写,让*和类型挨着写。
  3. 举例:
    #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、如何定义一个函数指针数组:

  1. 找到多个具有相同返回值类型、相同形参列表类型的函数:也就是我们数组保存的对象,确定它们的个数
    int getMax(int data1, int data2);
    int getMin(int data1, int data2);
    int getSum(int data1, int data2);

  2. 标准的写法:
    int (*pfunc[3])(int data1, int data2);	//函数指针数组

3、函数指针数组为啥这样写?(通用的类型判别方法):

  1. 函数指针数组是一个数组,根据优先级,[ ] 高于 *,所以先将pfunc与中括号结合,表明pfunc是一个数组;再和*结合,表示数组fpunc[3]里的元素是指针;然后根据优先级,*func[3]再和(int data1, int data2)结合,表明数组元素里的指针指向函数,最后和int结合,表示函数的返回值是int类型的。
  2. 适用于变量、指针、函数的类型判别方法:地位从高到底
    1. 找到变量名,若没有变量名,找到最里面的结构
    2. 向右看,读出看到的东西,不要跳过括号
    3. 向左看,读出看到的东西,不要跳过括号
    4. 若有括号,跳出第一层括号
    5. 重复上述过程,直到读出最终的类型

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,输出它们的最大值、最小值、和。

  1. 思路:
    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变量

  2. 代码:
    #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的功能:

  1. 知识点:【如何定义一个指针指向函数指针数组?】   从里往外读 ,遵循通用的类型判别方法 
  2. 思路:
    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

  3. 代码:
    #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;
    }

 

 

          

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值