本网站(662p.com)打包出售,且带程序代码数据,662p.com域名,程序内核采用TP框架开发,需要联系扣扣:2360248666 /wx:lianweikj
精品域名一口价出售:1y1m.com(350元) ,6b7b.com(400元) , 5k5j.com(380元) , yayj.com(1800元), jiongzhun.com(1000元) , niuzen.com(2800元) , zennei.com(5000元)
需要联系扣扣:2360248666 /wx:lianweikj
C语言超详细讲解指向函数的指针
xiaomei1994 · 248浏览 · 发布于2022-07-14 +关注

C语言程序在编译后,每个函数都有一个首地址(也就是函数第一条指令的地址),这个地址称为函数的指针。可以定义指向函数的指针变量,使用指针变量间接调用函数

一、函数的指针

首先,函数名代表函数的起始地址,调用函数时,程序会从函数名获取到函数起始地址,并从该地址起执行函数中的代码,函数名就是函数的指针,所以我们可以定义一个指向函数的指针变量,用来存放函数的起始地址,这样一来,就可以通过该变量来调用其所指向的函数。

二、指向函数的指针变量

定义指向函数的指针变量

返回值类型(* 指针变量名)(形参类型列表);

例如:int(*p)(int, int);,这行代码定义了一个可以指向返回值为整型且有两个整型形参函数的指针变量p,符合返回值为整型且有两个整型形参的函数都可以将其地址(即其函数名)赋给p。

使用指向函数的指针变量

在使用指向函数的指针变量时,只需要将函数名赋给指向函数的指针变量即可,因为函数名就是该函数的入口地址。

由于指向函数的指针变量保存了函数的地址,则该指针变量就指向了对应的函数。例如,求最大值的函数命名为max,如果将其函数名赋给指向函数的指针变量p(即p = max)后,则p就指向了max函数,并且可以通过(*p)(a, b);的方式来调用max函数,因为指针变量p保存了max函数的地址,那么*p就是max。需要注意的是,其中*p前的*可以省略,故也可以写成p(a, b);

三、调用函数的两种方式

引例:自定义max函数,求整数a和b中的较大者并返回给主调函数,不考虑两数相等的情况通过函数名调用函数

#include <stdio.h>
int max(int, int); // max函数的函数声明
int main()
{
    int a, b;
    printf("请输入两个整数:");
    scanf("%d%d", &a, &b);
    printf("两数中的较大者的值为%d\n", max(a, b));
    return 0;
}
int max(int a, int b)
{
    if (a > b)
        return a;
    else
        return b;
}

通过指向函数的指针变量调用函数

#include <stdio.h>
int max(int, int); // max函数的函数声明
int main()
{
    int a, b;
    int(*p)(int, int); // 定义指向函数的指针p
    p = max; // p指向max函数
    printf("请输入两个整数:");
    scanf("%d%d", &a, &b);
    printf("两数中的较大者的值为%d\n", (*p)(a, b)); // (*p)(a, b) 也可写为 p(a, b)
    return 0;
}
int max(int a, int b)
{
    if (a > b)
        return a;
    else
        return b;
}

四、指向函数的指针的作用

看到这里有人可能会问,既然函数名就可以调用函数,为什么还要弄个奇奇怪怪的指针?这难道不是多此一举嘛?难倒是为了装13?不管怎样,使用指向函数的指针来调用函数肯定不是为了装13,主要的原因是:用函数名调用函数时比较死板,只能调用所指定的一个函数,而通过指针变量调用函数会比较灵活,可以根据不同的情况调用不同的函数。以下面的程序为例: 输入两个整数,然后让用户选择1或2,选1则调用max函数求出两个整数的较大者并将其输出,选2则调用min函数求出两个整数的较小者并将其输出,不考虑两数相等的情况

#include <stdio.h>
int max(int, int); // max函数的函数声明
int min(int, int); // min函数的函数声明
int main()
{
    int a, b, c, n;
    int (*p)(int, int); // 定义指向函数的指针p
    p = NULL; // 先将p赋为空
    printf("请输入两个整数:");
    scanf("%d%d", &a, &b);
    printf("输入1获取两个数中的较大者,输入2获取两个数中的较小者,请输入:");
    scanf("%d", &n);
    if (n == 1)
        p = max; // p指向max函数
    else if (n == 2)
        p = min; // p指向min函数
    c = p(a, b); // 调用p所指向的函数
    if (n == 1)
        printf("两个数中的较大者为:%d\n", c);
    else
        printf("两个数中的较小者为:%d\n", c);
    return 0;
}
int max(int a, int b)
{
    if (a > b)
        return a;
    else
        return b;
}
int min(int a, int b)
{
    if (a < b)
        return a;
    else
        return b;
}

五、用指向函数的指针作函数参数(重点)

指向函数的指针变量的一个重要用途是把函数的入口地址作为实参传递给其他函数。以下面的程序为例:

有两个整数a和b,由用户输入1,2,3来决定进行什么操作。输入1则求出a和b中的较大者,输入2则求出a和b中的较小者,输入3则求出a与b之和,不考虑两个数相等的情况

#include <stdio.h>
int fun(int, int, int (*p)(int, int));
int max(int, int);
int min(int, int);
int sum(int, int);
int main()
{
    int a = 34, b = -21, n;
    printf("输入1获得两数中的较大者,输入2获得两数中的较小者,输入3获得两个数的和,请输入:");
    scanf("%d", &n);
    if (n == 1)
        printf("两数中的较大者为%d\n", fun(a, b, max));
        // 向fun函数中传参时,只需要传入两个整数或整型变量以及想要在fun函数内执行的函数的函数名即可
        // 函数名会传递给对应的形参指针变量
    else if (n == 2)
        printf("两数中的较小者为%d\n", fun(a, b, min));
    else if (n == 3)
        printf("两个数的和为%d\n", fun(a, b, sum));
    return 0;
}
// fun函数的作用是获取最终结果
int fun(int x, int y, int (*p)(int, int))
{
    int result;
    result = p(x, y); // 用result接收最终结果,不管执行max,min,sum中的哪个函数,fun函数内部代码都不用改变
    return result;
}
int max(int x, int y)
{
    if (x > y)
        return x;
    else
        return y;
}
int min(int x, int y)
{
    if (x < y)
        return x;
    else
        return y;
}
int sum(int x, int y)
{
    return x + y;
}

从上面的程序中可以清晰地看出,不管调用max,min,sum中的哪个函数,fun函数均没有任何变化,在fun函数内部的result只用来获取结果并将结果返回,但不去判断到底要通过哪个函数来计算这一结果,主调函数向其传入哪个函数,其内部就执行哪个函数。max,min,sum函数用来计算,fun函数用来获取结果,这体现出了整个程序的模块化。

六、为什么要将指向函数的指针变量作为函数的形参(重点)

举一个例子,我们在学习数组的过程中,想要把数组中的所有元素输出,通常会接触一个新词,遍历。其实遍历的含义并不是将一个结构中的元素输出的过程,然而我在初学时便认为遍历等同于输出,这是我在初学时对遍历这个词不准确的理解,我相信也一定有人跟我一样这样认为。其实遍历指的是依次访问某种结构中的所有元素,至于对这些元素怎么操作,由程序员自己决定,比如,你想输出所有的元素,那就可以调用输出函数将每次获取到的元素输出;你想将所有元素的值翻倍,那就调用对应的翻倍函数将每次获取到的元素翻倍。但是这样一来,遍历函数的功能就变得十分单一,只能进行一种操作,要么是遍历并输出,要么是遍历并翻倍,如果在一个程序中,开始想要遍历并翻倍,后又想要遍历并输出,就只能定义两个函数来实现,但是我们发现不管对元素怎么操作,访问每个元素的代码都是相同,并且只要想对结构中的每个元素进行操作,首先要做的就是访问每个元素。但是如果为了输出而定义一个先遍历后输出的函数,为了将每个元素的值翻倍而定义一个先遍历后翻倍的函数,这样遍历元素的代码就是重复的。那要怎么办呢?既然遍历的操作是重复的,那我们就定义一个专门的遍历函数,该函数只用来访问元素,再定义其它多个操作数据的函数,至于我们对遍历后的数据执行什么样的操作,我们只需要将对应的操作函数通过遍历函数的形参接收过来,这样就可以实现在遍历函数中根据不同情况执行不同操作的目的,如此一来既体现出了程序设计的结构化与模块化,又减少了编程时的代码量。


c

相关推荐

PHP实现部分字符隐藏

沙雕mars · 1325浏览 · 2019-04-28 09:47:56
Java中ArrayList和LinkedList区别

kenrry1992 · 908浏览 · 2019-05-08 21:14:54
Tomcat 下载及安装配置

manongba · 970浏览 · 2019-05-13 21:03:56
JAVA变量介绍

manongba · 962浏览 · 2019-05-13 21:05:52
什么是SpringBoot

iamitnan · 1086浏览 · 2019-05-14 22:20:36
加载中

0评论

评论
分类专栏
小鸟云服务器
扫码进入手机网页