【C语言进阶】——指针(二) (函数指针,回调函数,qsort排序)(中)

简介: 【C语言进阶】——指针(二) (函数指针,回调函数,qsort排序)(中)

6、函数指针数组

数组是一个存放相同类型数据的存储空间,那我们已经学习了指针数组,比如︰

int* arr[10];
//数组的每个元素是int*

那要把函数的地址存到一个数组中,那这个数组就叫函数指针数组,那函数指针的数组如何定义呢 ?

int ( *parr1[10] )( ); √

int* parr2[10] ( ); x

int (*)( ) parr3[10]; x

答案是:parr1 parr1先和[结合,说明parr1是数组。
数组的内容是什么呢 ?
是int(*)()类型的函数指针。


#include <stdio.h>
int Add(int x, int y)
{
    return x + y;
}
int Sub(int x, int y)
{
    return x - y;
}
int Mul(int x, int y)
{
    return x * y;
}
int Div(int x, int y)
{
    return x / y;
}

int main()
{
    //指针数组
    //int* arr[5];
    int (*pa)(int, int) = Add;//Sub/Mul/Div
    //需要一个数组,这个数组可以存放4个函数的地址 - 函数指针的数组
    int(*parr[4])(int, int) = {Add, Sub, Mul, Div};//函数指针的数组
    int i = 0;
    for (i = 0; i < 4; i++)
    {
        printf("%d\n", parr[i](2, 3));//5 -1 6 0
    }
    return 0;
}

【C语言进阶】——指针(二) (函数指针,回调函数,qsort排序) _回调函数_12


练习:

定义一个函数;

char* my_strcpy (char* dest, const char* src);

练习要求:

1.写一个函数指针pf,能够指向my——strcpy
2.写一个函数指针数组 pfArr,能够存放4个my_strcpy函数的地址

答案:

1.char* (pf)(char, const char * )
2.char
(*pfArr[4])(char, const char *)


1.函数指针数组的用途

2.制作计算器

转移表 —《C和指针》这本书提及

请看下面简易计算器的例子:

1.使用switch……case语句

#include<stdio.h>
void cal_menu()
{
    printf("*****************************\n");
    printf("*****   1.Add     2.Sub  ****\n");
    printf("*****   3.Mul     4.Div  ****\n");
    printf("******    0.exit     ********\n");
    printf("*****************************\n");
}
int Add(int x, int y)
{
    return x + y;
}
int Sub(int x, int y)
{
    return x - y;
}
int Mul(int x, int y)
{
    return x * y;
}
int Div(int x, int y)
{
    return x / y;
}
int main()
{
    int input;//根据菜单提示输入操作符
    int x = 0;
    int y = 0;
    do
    {
        cal_menu();
        printf("请选择操作符:>>\n");
        scanf("%d", &input);
        printf("请输入两个操作数:>>\n");
        scanf("%d%d", &x, &y);
        switch (input)
        {
        case 1:
            printf("%d\n", Add(x, y));
            break;
        case 2:
            printf("%d\n", Sub(x, y));
            break;
        case 3:
            printf("%d\n", Mul(x, y));
            break;
        case 4:
            printf("%d\n", Div(x, y));
            break;
        case 0:
            printf("退出!\n");
            break;
        default:
            printf("选择错误!\n");
            break;
        }
    } while (input);
    return 0;
}

【C语言进阶】——指针(二) (函数指针,回调函数,qsort排序) _函数指针数组_13

这里我们用函数调用的方式实现两个数之间的加、减、乘、除操作,但是当我们想要退出程序的时候,选择0并不能之间退出游戏,还需要进行输入两个操作数,这种方式明显不符合我们的预期,对其稍微进行改造以下:


方法一:

下面我们通过函数指针数组的方式来实现吧!

#include<stdio.h>
void cal_menu()
{
    printf("*****************************\n");
    printf("*****   1.Add     2.Sub  ****\n");
    printf("*****   3.Mul     4.Div  ****\n");
    printf("******    0.exit     ********\n");
    printf("*****************************\n");
}
int Add(int x, int y)
{
    return x + y;
}
int Sub(int x, int y)
{
    return x - y;
}
int Mul(int x, int y)
{
    return x * y;
}
int Div(int x, int y)
{
    return x / y;
}
int main()
{
    int input;//根据菜单提示输入操作符
    int x = 0;
    int y = 0;
    int(*pArr[])(int, int) = { 0,Add,Sub,Mul,Div };
    do
    {
        cal_menu();
        printf("请选择操作符:>>\n");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
        case 2:
        case 3:
        case 4:
            printf("请输入两个操作数:>>\n");
            scanf("%d%d", &x, &y);
            printf("%d\n", (*pArr[input])(x, y)); //通过input找到 函数 加减乘除
            break;
        case 0:
            printf("退出!\n");
            break;
        default:
            printf("选择错误!\n");
            break;
        }

    } while (input);
    return 0;
}

【C语言进阶】——指针(二) (函数指针,回调函数,qsort排序) _qsort函数排序_14


利用函数指针数组的方式,不仅可以简化我们的代码,也可以方面后面的扩展,比如说后面我们添加一个取模功能或一个异或功能,整个代码仅仅需要进行细微的调整即可满足我们的要求:

#include<stdio.h>
void cal_menu()
{
    printf("*****************************\n");
    printf("*****   1.Add     2.Sub  ****\n");
    printf("*****   3.Mul     4.Div  ****\n");
    printf("*****   5.Mod     6.Xor  ****\n");
    printf("******    0.exit     ********\n");
    printf("*****************************\n");
}
int Add(int x, int y)
{
    return x + y;
}
int Sub(int x, int y)
{
    return x - y;
}
int Mul(int x, int y)
{
    return x * y;
}
int Div(int x, int y)
{
    return x / y;
}
int Mod(int x, int y)
{
    return x % y;
}
int Xor(int x, int y)
{
    return x ^ y;
}
int main()
{
    int input;//根据菜单提示输入操作符
    int x = 0;
    int y = 0;
    int(*pArr[])(int, int) = { 0,Add,Sub,Mul,Div,Mod,Xor };
    do
    {
        cal_menu();
        printf("请选择操作符:>>\n");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
            printf("请输入两个操作数:>>\n");
            scanf("%d%d", &x, &y);
            printf("%d\n", (*pArr[input])(x, y));
            break;
        case 0:
            printf("退出!\n");
            break;
        default:
            printf("选择错误!\n");
            break;
        }

    } while (input);
    return 0;
}

【C语言进阶】——指针(二) (函数指针,回调函数,qsort排序) _回调函数_15

这个地方我们仅仅调整了打印的菜单栏,函数指针数组初始化的值以及switch语句中加上case 5,case6。即可满足我们的要求,后续如果进行更多的功能扩展也可以按照这种方式,非常简单。


通过函数指针来实现

printf("请输入两个操作数:>>\n");
scanf("%d%d", &x, &y);
printf("%d\n", Add(x, y));

我们将这个重复的代码封装到一个函数中:

void cal_menu()
{
    printf("*****************************\n");
    printf("*****   1.Add     2.Sub  ****\n");
    printf("*****   3.Mul     4.Div  ****\n");
    printf("******    0.exit     ********\n");
    printf("*****************************\n");
}
int Add(int x, int y)
{
    return x + y;
}
int Sub(int x, int y)
{
    return x - y;
}
int Mul(int x, int y)
{
    return x * y;
}
int Div(int x, int y)
{
    return x / y;
}
void Calc(int (*pf)(int, int))
{
    int x = 0;
    int y = 0;
    printf("请输入两个操作数:>>\n");
    scanf("%d%d", &x, &y);
    printf("%d\n", pf(x, y)); //(*)可以省略
}
int main()
{
    int input;//根据菜单提示输入操作符

    do
    {
        cal_menu();
        printf("请选择操作符:>>\n");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
            Calc(Add);
            break;
        case 2:
            Calc(Sub);
            break;
        case 3:
            Calc(Mul);
            break;
        case 4:
            Calc(Div);
            break;
        case 0:
            printf("退出!\n");
            break;
        default:
            printf("选择错误!\n");
            break;
        }
    } while (input);
    return 0;
}


方法二:

//简易计算器

//菜单函数部分与计算函数部分
#include <stdio.h>
void menu()
{
    printf("**************************\n");
    printf("**  1. add       2. sub **\n");
    printf("**  3. mul       4. div **\n");
    printf("**  5. xor       0. exit**\n");
    printf("**************************\n");
}

int Add(int x, int y)
{
    return x + y;
}

int Sub(int x, int y)
{
    return x - y;
}

int Mul(int x, int y)
{
    return x * y;
}

int Div(int x, int y)
{
    return x / y;
}

int Xor(int x, int y)
{
    return x ^ y;
}

//主函数部分,实现计算函数调用
//使用函数指针数组
int main()
{
    int input = 0;
    int x = 0;
    int y = 0;
    //pfArr 是一个函数指针数组 - 转移表
    int(*pfArr[])(int, int) = { 0, Add, Sub, Mul, Div, Xor };
    do
    {
        menu();
        printf("请选择:>");
        scanf("%d", &input);
        if (input >= 1 && input <= 5)
        {
            printf("请输入两个操作数:>");
            scanf("%d%d", &x, &y);
            int ret = pfArr[input](x, y);//通过指针找到相应的函数
            printf("%d\n", ret);
        }
        else if (input == 0)
        {
            printf("退出\n");
        }
        else
        {
            printf("选择错误\n");
        }
    } while (input);
    return 0;
}


7、指向函数指针数组的指针

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

例如:

void cal_menu()
{
    printf("*****************************\n");
    printf("*****   1.Add     2.Sub  ****\n");
    printf("*****   3.Mul     4.Div  ****\n");
    printf("******    0.exit     ********\n");
    printf("*****************************\n");
}

int Add(int x, int y)
{
    return x + y;
}
int Sub(int x, int y)
{
    return x - y;
}
int Mul(int x, int y)
{
    return x * y;
}
int Div(int x, int y)
{
    return x / y;
}

void Calc(int (*pf)(int, int))  //函数地址 传到(*pf)接收
{
    int x = 0;
    int y = 0;
    printf("请输入两个操作数:>>\n");
    scanf("%d%d", &x, &y);
    printf("%d\n",*pf)(x, y));  //(*)可以省略
}

int main()
{
    int input;//根据菜单提示输入操作符

    do
    {
        cal_menu();
        printf("请选择操作符:>>\n");
        scanf("%d", &input);
        switch (input)
        {
        case 1:
            Calc(Add);
            break;
        case 2:
            Calc(Sub);
            break;
        case 3:
            Calc(Mul);
            break;
        case 4:
            Calc(Div);
            break;
        case 0:
            printf("退出!\n");
            break;
        default:
            printf("选择错误!\n");
            break;
        }
    } while (input);
    return 0;
}

【C语言进阶】——指针(二) (函数指针,回调函数,qsort排序) _qsort函数排序_16

这种方法代码也比较简洁,扩展性也比较好。
这种方法利用了回调函数,后面会详解回调函数!


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

int Add(int x, int y)
{
    return x + y;
}

int main()
{
    int arr[10] = { 0 };
    int (*p)[10] = &arr;//取出数组的地址
    int(*p)[10] = &arr;//数组指针
    char arr1[5] = { 0 };//字符数组
    char* (*p1)[5] = &arr1;//字符数组指针

    
    int(*pf)(int, int)=Add ;//函数指针
    int (*pfArr[4])(int, int);//pfArr是一个数组-函数指针的数组
    
    //ppfArr是一个指向[函数指针数组]的指针
    int(*(*ppfArr)[4])(int, int) = &pfArr;//指向函数数组指针的指针
    //ppfArr 是一个数组指针,指针指向的数组有4个元素
    //指向的数组的每个元素的类型是一个函数指针 int(*)(int, int)
    
    return 0;
}


如何写出指向函数指针数组的指针呢?
方法一:

①首先我们应该要知道该指针指向的函数指针数组到底是什么?以上面的代码为例:对应的函数指针数组是:int(p3[4])(int, int) = { 0 }; 该函数指针数组的类型是:int()(int, int) //去掉变量名p3和数组[4]剩下的就是数组的类型 int(*)(int,int)
②用指向函数指针数组的指针变量名替换原来的数组变量名,也就是用(p4)替换p3得到的就是int((*p4)[4])(int, int) = &p3;//指向函数指针数组的指针

方法二:

①指向函数指针数组的指针本质上也是指针,所以我们首先写(p4),这个指针指向的一个数组,数组元素个数是4,所以右边要紧接着加上[4],
变成(p4)[4]
②此时要清楚知道数组的元素类型,以上面的代码为例:对应的函数指针数组是:int(p3[4])(int, int) = { 0 }; 该函数指针数组的类型是:int()(int, int) 将①中写好的内容(p4)[4],放到类型int()(int,int) 后面,得到:
int((*p4)[4])(int, int)//指向函数指针数组的指针

扩展:如果我们要继续往下写一个指向函数指针数组的指针数组,可以这样写:

int(*(*p4[3])[4])(int, int)//指向函数指针数组的指针数组


目录
相关文章
|
23天前
|
搜索推荐 C语言 C++
【C指针(五)】6种转移表实现整合longjmp()/setjmp()函数和qsort函数详解分析&&模拟实现3
【C指针(五)】6种转移表实现整合longjmp()/setjmp()函数和qsort函数详解分析&&模拟实现
|
1天前
|
存储 算法 C语言
C语言进阶:顺序表(数据结构基础) (以通讯录项目为代码练习)
C语言进阶:顺序表(数据结构基础) (以通讯录项目为代码练习)
|
16天前
|
存储 C语言
C语言 — 指针进阶篇(下)
C语言 — 指针进阶篇(下)
20 0
|
16天前
|
存储 C语言 C++
C语言 — 指针进阶篇(上)
C语言 — 指针进阶篇(上)
26 0
|
19天前
|
存储 测试技术 C语言
【C语言进阶】 假期测评③
【C语言进阶】 假期测评③
41 1
|
22天前
|
存储 程序员 C语言
C语言指针的概念、语法和实现
在C语言中,指针是其最重要的概念之一。 本文将介绍C语言指针的概念、语法和实现,以及如何使用它们来编写高效的代码。
13 0
|
24天前
|
C语言 索引
基于C语言的函数指针应用-消息命令处理框架
基于C语言的函数指针应用-消息命令处理框架
11 0
|
28天前
|
搜索推荐 算法 编译器
【C语言】qsort()函数详解:能给万物排序的神奇函数
【C语言】qsort()函数详解:能给万物排序的神奇函数
41 0
|
1月前
|
存储 人工智能 编译器
C语言指针详解
指针运算,指针和数组,二级指针
C语言指针详解
|
1月前
|
存储 C语言
C语言第二十四弹---指针(八)
C语言第二十四弹---指针(八)