15-C语言:第15~16天笔记

函数指针

定义

函数指针本质上是指针,是一个指向函数的指针。函数都有一个入口地址,所谓指向函数

的指针,就是指向函数的入口地址。(这里的函数名就代表入口地址)

函数指针存在的意义:

  • 让函数多了一种调用方式
  • 函数指针可以作为形参,可以形式调用(回调函数)

遵循:先有函数,后有指针

语法:

复制代码
返回类型 (*指针变量名)(形参列表);

举例:

复制代码
int (*fun)(int a, int b);

int (*fun)(int, int); // 有点类似于函数声明

函数指针的初始化

① 定义的同时赋值

复制代码
// 函数指针需要依赖于函数,先有函数,后有指针
// 定义一个普通函数
int add(int a, int b) { return a + b; }
// 定义一个函数指针,并初始化
// 观察:函数指针的返回类型和指向的函数的返回类型一致,函数指针的形参个数、类
型、位置和指向的函数的参数的一致。
int (*p)(int a, int b) = add; // 函数指针p指向函数add,这里的add不能带(),
add就表示函数的入口地址

② 先定义,后赋值

复制代码
// 定义一个普通函数

int add(int a, int b) { return a + b; }

int (*p)(int, int); // 形参列表的参数名可以省略不写

p = add; // 此时是将add的入口地址赋值给指针p

注意:

  1. 函数指针指向的函数要和函数指针定义的返回值类型,形参列表对应,否则编

译报错

  1. 函数指针是指针,但不能指针运算,如p++等,没有实际意义
  2. 函数指针作为形参,可以形成回调
  3. 函数指针作为形参,函数调用时的实参只能是与之对应的函数名,不能带小括

号()

  1. 函数指针的形参列表中的变量名可以省略

注意:函数不能作为函数的形参,但是指向函数的函数指针是可以作为函数的形参的。

案例

需求:求a,b两个数的最大值

代码:

复制代码
#include <stdio.h>

/**

\* 定义一个函数,求两个数的最大值

*/

int get_max(int a, int b)

{

return a > b ? a : b;

}

int main(int argc,char *argv[])

{

    // 定义测试数据

    int a = 3, b = 4, max;

    // 直接调用函数

    max = get_max(a, b);

    printf("%d,%d中的最大值是:%d\n",a,b,max);

    // 定义一个函数指针

    int (*p)(int, int) = get_max;

    // 间接调用函数:方式1

    max = p(a,b);

    printf("%d,%d中的最大值是:%d\n",a,b,max);

    // 间接调用函数:方式2

    max = (*p)(a,b); // () > [] > *

    printf("%d,%d中的最大值是:%d\n",a,b,max);
    return 0;
}

回调函数

定义

复制代码
	==回调函数就是一个通过函数指针调用的函数==。如果你把函数的指针作为参数传递给另

一个函数,当这个指针被用来调用其所指向的函数时。我们就说这是回调函数。回调函数

不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,

用于对该事件或条件进行响应。

​ 简单来说,就是使用函数指针作为函数的形参,这种函数就被称作回调函数。

为什么要用回调函数

​ 因为可以把调用者与被调用者分开,所以调用者不关心谁是被调用者。它只需知道存

在一个具有特定原型和限制条件的被调用函数。

​ 简而言之,回调函数就是允许用户把需要调用的方法的指针作为参数传递给一个函

数,以便该函数在处理相似事件的时候可以灵活的使用不同的方法。

案例

复制代码
#include <stdio.h>
/**
\* 回调函数1

*/

int callback_1(int a)

{

    printf("hello, this is callback_1:a=%d\n", a);

    return a;

}

/**

\* 回调函数2

*/

int callback_2(int b)

{

    printf("hello, this is callback_2:b=%d\n", b);

    return b;

}

/**

\* 回调函数3

*/

int callback_3(int c)

{

    printf("hello, this is callback_3:c=%d\n", c);

    return c;

}

/**

\* 实现回调函数(形参是函数指针的函数)

*/

int handle(int x, int (*callback)(int))

{

    printf("日志:开始执行任务!\n");

    int res = callback(x);

    printf("日志:执行结果:%d\n",res);

    printf("日志:结束执行任务!\n");

}

int main(int argc,char *argv[])

{

    handle(100,callback_1);

    handle(200,callback_2);

    handle(300,callback_3);

return 0;

}

运行结果:

二级指针

定义

​ 二级指针(多重指针)用于储存一级指针的地址,需要两次解引用才能访问原始数据。其

他多重指针的用法类似,但实际开发中最常见的指针是二级指针。

复制代码
int a = 10; // a是普通变量,也就是原始数据
int *p = &a; // 一级指针,p指向a,解引用1次就可以获取a的值
printf("%d\n", *p); // 10

int **w = &p; // 二级指针,w指向p,解引用2次就可以获取a的值
printf("%d\n", **w);// 10

int ***k = &w; // 三级指针,k指向w,解引用3次就可以获取a的值
printf("%d\n", ***k); // 10 int a1 = ***k; int *a2 = **k; int **a3
= *k; int ***a4 = k;
语法

数据类型 **指针变量名 = 指针数组的数组名 | 一级指针的地址

特点

与指针数组的等效性 二级指针与指针数组在某些时候存在等效性,但与二维数组不等

效。二维数组名是数组指针类型,如 int (*)[3] ,而非二级指针。

复制代码
// 指针数组
int arr[] = {11,22,33};
int *arr_[] = {&arr[0],&arr[1],&arr[2]};
// 二级指针接收指针数组
char *str[3] = {"abc","aaa034","12a12"};
char **p = str; // p:数组首地址,行地址,默认0行 *p:列地址,默认0行0列
**p:列元素

#include <stdio.h>
int main(int argc,char *argv[])
{
    char *str[3] = {"abc","aaa034","12a12"};
    char **p = str;
    // 打印字符串
    // for (int i = 0; i < 3; i++)
    // {
        // printf("%s\n", *p);
        // p++;
    // }
    // 打印字符
    int i = 0;
    while(**p != '\0')
    {
        printf("%-2c",**p);
        (*p)++;
    }
    printf("\n");
    return 0;
}

与二维数组的差异 二维数组名是数组指针类型,直接赋值给二级指针会导致类型不匹

复制代码
// 数组指针可以指向一个二维数组
int arr[2][3] = {{1,3,5},{11,33,55}};
int (*p)[3] = arr;
// 二级指针不等效二维数组
int **k = arr; // 编译报错 arr类型 int(*)[3] 不兼容 k类型 int**

0')

{

printf("%-2c",**p);

(*p)++;

}

printf("\n");

return 0;

}

复制代码
② **与二维数组的差异** 二维数组名是数组指针类型,直接赋值给二级指针会导致类型不匹

配

// 数组指针可以指向一个二维数组

int arr[2][3] = {{1,3,5},{11,33,55}};

int (p)[3] = arr;
// 二级指针不等效二维数组
int **k = arr; // 编译报错 arr类型 int(
)[3] 不兼容 k类型 int**

复制代码
相关推荐
Eloudy11 分钟前
简明量子态密度矩阵理论知识点总结
算法·量子力学
点云SLAM12 分钟前
Eigen 中矩阵的拼接(Concatenation)与 分块(Block Access)操作使用详解和示例演示
人工智能·线性代数·算法·矩阵·eigen数学工具库·矩阵分块操作·矩阵拼接操作
悠哉悠哉愿意14 分钟前
【电赛学习笔记】MaixCAM 的OCR图片文字识别
笔记·python·嵌入式硬件·学习·视觉检测·ocr
算法_小学生2 小时前
支持向量机(SVM)完整解析:原理 + 推导 + 核方法 + 实战
算法·机器学习·支持向量机
_Kayo_2 小时前
VUE2 学习笔记5 动态绑定class、条件渲染、列表过滤与排序
笔记·学习
iamlujingtao2 小时前
js多边形算法:获取多边形中心点,且必定在多边形内部
javascript·算法
算法_小学生2 小时前
逻辑回归(Logistic Regression)详解:从原理到实战一站式掌握
算法·机器学习·逻辑回归
慕容白 MU2 小时前
新唐51单片机看门狗配置流程
c语言·单片机·嵌入式硬件·51单片机
DebugKitty3 小时前
C语言14-指针4-二维数组传参、指针数组传参、viod*指针
c语言·开发语言·算法·指针传参·void指针·数组指针传参
qystca3 小时前
MC0241防火墙
算法