当前位置: 首页 > news >正文

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;// 间接调用函数:方式1max = p(a,b);printf("%d,%d中的最大值是:%d\n",a,b,max);// 间接调用函数:方式2max = (*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); // 10int **w = &p; // 二级指针,w指向p,解引用2次就可以获取a的值
printf("%d\n", **w);// 10int ***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**

http://www.dtcms.com/a/304126.html

相关文章:

  • FreeRTOS在中断上下文中设置事件组,调度很慢的的解决方法
  • 智慧工地系统:科技如何重塑建筑现场?
  • macOS “Sploitlight“漏洞曝光:攻击者可窃取Apple Intelligence缓存数据
  • 用动态的观点看加锁
  • 新升级超值型系列32位单片机MM32G0005
  • C++类中动态内存分配注意手册
  • python新手,学习计划
  • 每日一题7.29
  • 当贝纯净版_海信ip811n海思mv320处理器安卓4.42及9.0主板优盘免拆刷机固件及教程
  • [Token]ALGM: 基于自适应局部-全局token合并的简单视觉Transformer用于高效语义分割, CVPR2024
  • 安卓逆向2-安卓刷机和获取root权限和安装LSPosed框架
  • 博物馆 VR 导览:图形渲染算法+智能讲解技术算法实现及优化
  • 想要批量提取视频背景音乐?FFmpeg 和转换器都安排上
  • 机器学习、深度学习与数据挖掘:三大技术领域的深度解析
  • centos7安装Docker
  • 机器学习、深度学习与数据挖掘:核心技术差异、应用场景与工程实践指南
  • Docker学习相关视频笔记(二)
  • Linux 系统启动与 GRUB2 核心操作指南
  • 7月29日星期二今日早报简报微语报早读
  • Ubuntu上开通Samba网络共享
  • Ubuntu22.04系统安装,Nvidia显卡驱动安装问题
  • RHCE综合项目:分布式LNMP私有博客服务部署
  • Ubuntu25.04轻量虚拟机Multipass使用Shell脚本自动创建并启动不同版本Ubuntu并复制文件
  • ubuntu22.04 安装 petalinux 2021.1
  • 【prompt】Lyra 提示词深度研究
  • Apache Ignite 关于 **负载均衡(Load Balancing)** 的详细介绍
  • 信创国产Linux操作系统汇总:从桌面到服务器,百花齐放
  • RAG面试内容整理-8. 文档分块策略(滑动窗口、语义切分)
  • pycharm自己的包导入不进去解决方案
  • 博途SCL: Input、Output、Static、Temp、Constant、InOut 的详细介绍及案例