C语言 — 指针进阶篇(下)

news2024/11/25 16:19:20

前言

指针基础篇回顾可以详见: 指针基础篇(1)指针基础篇(2)

指针进阶篇分为上下两篇,上篇介绍1 — 4,下篇介绍5 — 6

  1. 字符指针
  2. 数组指针
  3. 指针数组
  4. 数组传参和指针传参
  5. 函数指针
  6. 函数指针数组
  7. 指向函数指针数组的指针
  8. 回调函数

文章目录

  • 前言
  • 一、函数指针
    • 1. 函数指针是什么
    • 2. 函数指针声明
  • 二、函数指针数组
    • 1. 函数指针数组是什么
    • 2. 举例说明
  • 三、指向函数指针数组的指针
    • 1. 指向函数指针数组的指针是什么
    • 2.举例说明
  • 四、回调函数
    • 1. 回调函数是什么
    • 2.举例说明
  • 五、总结

一、函数指针

1. 函数指针是什么

函数指针指向函数的指针
函数指针是一个指向函数的指针变量。它可以保存某个函数的地址,并通过该指针变量调用相应的函数。使用函数指针可以方便地实现回调函数、代码复用等功能。

代码演示

#include <stdio.h>
void test()
{
 printf("hehe\n");
}
int main()
{
 printf("%p\n", test);
 printf("%p\n", &test);
 return 0;
}

输出结果

在这里插入图片描述
结论

输出的都是 test 函数的地址,&test(取地址函数名)和 test(函数名)都是函数的地址。


2. 函数指针声明

函数指针声明的一般格式如下:

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

其中,指针变量名是指向函数的指针变量的名称,返回类型参数列表分别是指向函数的指针变量所指向函数的返回值类型和参数类型列表。

演示代码

#include <stdio.h>
int add(int x,int y)
{
	return x + y;
}
int main()
{
	//int (*pr)(int, int) = add;
	int (*pr)(int, int) = &add;
	//int ret = (*pr)(4, 5);  //使用函数指针调用
	int ret = pr(4,5);//也可以这样写
	printf("%d", ret);
	return 0;
}

以下是函数指针变量

int (*pr)(int, int) = add;
int (*pr)(int, int) = &add;

函数指针调用函数,通过指针间接访问函数

int ret = (*pr)(4, 5);*号时一定要带括号
int ret = pr(4,5);

二、函数指针数组

1. 函数指针数组是什么

函数指针数组是由一组函数指针组成的数组。可以通过函数指针数组来存储多个不同的函数,并根据需要来选择调用适当的函数。


2. 举例说明

例如,让我们创建一个函数指针数组来存储三个函数,每个函数都有一个参数,返回一个整数:

int add(int x) 
{
  return x + 1;
}
int subtract(int x) 
{
  return x - 1;
}
int multiply(int x) 
{
  return x * 2;
}
int main()
{
	int (*function_array[3])(int) = { add, subtract, multiply };
	return 0;
}

这将创建一个名为 function_array 的数组,其包含三个函数指针。使用该数组可以调用相应的函数:

int result = 0;
result = function_array[0](3);  // 调用 add 函数,返回 4
result = function_array[1](3);      // 调用 subtract 函数,返回 2
result = function_array[2](3);      // 调用 multiply 函数,返回 6

函数指针数组是在需要动态选择和调用函数的情况下非常有用的。

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

1. 指向函数指针数组的指针是什么

指向函数指针数组的指针是一个指针,它指向一个函数指针数组的首元素。这个指针可以用来访问数组中的每个函数指针。例如:


2.举例说明

void (*func_ptr_array[2])(int); // 声明一个包含两个函数指针的数组

void func1(int x) {
    printf("func1: %d\n", x);
}

void func2(int x) {
    printf("func2: %d\n", x);
}

int main() {
    func_ptr_array[0] = func1;
    func_ptr_array[1] = func2;

    void (**ptr_to_func_ptr_array)(int) = func_ptr_array; // 声明一个指向函数指针数组的指针,初始化为函数指针数组的首元素

    (*ptr_to_func_ptr_array[0])(10); // 调用第一个函数指针,输出 "func1: 10"
    (*ptr_to_func_ptr_array[1])(20); // 调用第二个函数指针,输出 "func2: 20"

    return 0;
}

在上面的例子中,我们声明了一个包含两个函数指针的数组 func_ptr_array,并将它们分别初始化为 func1func2。然后,我们声明了一个指向函数指针数组的指针 ptr_to_func_ptr_array,并将它初始化为 func_ptr_array 的首元素。最后,我们使用指针 ptr_to_func_ptr_array 访问数组中的每个函数指针,并通过它们调用对应的函数。指向函数指针数组的指针是一个指针,它指向一个函数指针数组的首元素。这个指针可以用来访问数组中的每个函数指针。例如:

void (*func_ptr_array[2])(int); // 声明一个包含两个函数指针的数组

void func1(int x) {
    printf("func1: %d\n", x);
}

void func2(int x) {
    printf("func2: %d\n", x);
}

int main() {
    func_ptr_array[0] = func1;
    func_ptr_array[1] = func2;

    void (**ptr_to_func_ptr_array)(int) = func_ptr_array; // 声明一个指向函数指针数组的指针,初始化为函数指针数组的首元素

    (*ptr_to_func_ptr_array[0])(10); // 调用第一个函数指针,输出 "func1: 10"
    (*ptr_to_func_ptr_array[1])(20); // 调用第二个函数指针,输出 "func2: 20"

    return 0;
}

在上面的例子中,我们声明了一个包含两个函数指针的数组 func_ptr_array,并将它们分别初始化为 func1func2。然后,我们声明了一个指向函数指针数组的指针 ptr_to_func_ptr_array,并将它初始化为 func_ptr_array 的首元素。最后,我们使用指针 ptr_to_func_ptr_array 访问数组中的每个函数指针,并通过它们调用对应的函数。指向函数指针数组的指针是一个指针,它指向一个函数指针数组的首元素。这个指针可以用来访问数组中的每个函数指针。例如:

void (*func_ptr_array[2])(int); // 声明一个包含两个函数指针的数组

void func1(int x) {
    printf("func1: %d\n", x);
}

void func2(int x) {
    printf("func2: %d\n", x);
}

int main() {
    func_ptr_array[0] = func1;
    func_ptr_array[1] = func2;

    void (**ptr_to_func_ptr_array)(int) = func_ptr_array; // 声明一个指向函数指针数组的指针,初始化为函数指针数组的首元素

    (*ptr_to_func_ptr_array[0])(10); // 调用第一个函数指针,输出 "func1: 10"
    (*ptr_to_func_ptr_array[1])(20); // 调用第二个函数指针,输出 "func2: 20"

    return 0;
}

在上面的例子中,我们声明了一个包含两个函数指针的数组 func_ptr_array,并将它们分别初始化为 func1func2。然后,我们声明了一个指向函数指针数组的指针 ptr_to_func_ptr_array,并将它初始化为 func_ptr_array 的首元素。最后,我们使用指针 ptr_to_func_ptr_array 访问数组中的每个函数指针,并通过它们调用对应的函数。

四、回调函数

1. 回调函数是什么

回调函数是一种函数,它作为参数传递给另一个函数。当调用该函数时,它将执行传递的回调函数。这种技术通常用于异步编程中,因为它允许程序在等待某些操作完成时执行其他任务。回调函数通常用于处理结果和错误,以便相应地处理它们。

2.举例说明

下面是一个简单的C语言回调函数的示例:

#include <stdio.h>

void callback(int x) {
    printf("The square of %d is %d\n", x, x*x);
}

void operate(int x, void (*cb)(int)) {
    cb(x);
}

int main() {
    operate(5, callback); //将callback作为operate函数的参数传递
    return 0;
}

在这个示例中,callback函数被定义为一个回调函数,它接受一个整数参数x并输出其平方。operate函数也被定义,它接受一个整数参数x和一个回调函数指针cb作为参数。在main函数中,我们将callback函数作为参数传递给operate函数,并将整数5作为第一个参数传递。当operate函数完成其操作(这里是输出平方值)时,它将调用传递的回调函数cb,并将操作结果作为参数传递给它,从而实现异步事件处理和代码逻辑分离。下面是一个简单的C语言回调函数的示例:

五、总结

本期博客介绍了函数指针、函数指针数组、指向函数指针数组的指针、回调函数

  1. 函数指针:函数指针是一个指向函数的指针变量。
  2. 函数指针数组:是由一组函数指针组成的数组。
  3. 指向函数指针数组的指针:是一个指针,它指向一个函数指针数组的首元素。
  4. 回调函数:是一种函数,它作为参数传递给另一个函数。

如这篇博客对大家有帮助的话,希望 三连 支持一下 !!! 如果有错误感谢大佬的斧正 如有 其他见解发到评论区,一起学习 一起进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/743129.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot 配置文件:什么是配置文件?配置文件是干什么?

文章目录 &#x1f387;前言1.配置文件的格式2. properties配置文件说明2.1 properties基本语法2.2 读取配置文件 3. yml 配置文件说明3.1 yml 基本语法 4.properties与yml 对比 &#x1f387;前言 学习一个东西&#xff0c;我们先要知道它有什么用处。整个项目中所有重要的数…

C语言,指针易错点

1、封装函数&#xff0c;用指针实现字符串连接 #include <stdio.h> #include <string.h> void MyStrcat(char *dest,char *src) {int i;for(i0;*(desti);i);for(int j0;*(srcj);j)*(desti)*(srcj);*(desti)0; } int main(int argc, const char *argv[]) {char des…

Spring详解(学习总结)

目录 一、Spring概述 &#xff08;一&#xff09;、Spring是什么&#xff1f; &#xff08;二&#xff09;、Spring框架发展历程 &#xff08;三&#xff09;、Spring框架的优势 &#xff08;四&#xff09;、Spring的体系结构 二、程序耦合与解耦合 &#xff08;一&…

MySQL与PostgreSQL的区别

MySQL与PostgreSQL的区别 PostgreSQL的特点包括&#xff1a; 1.PostgreSQL是一个免费的对象-关系数据库服务器 (ORDBMS)&#xff0c;在灵活的BSD许可证下发行。 2.PostgreSQL的Slogan是"世界上最先进的开源关系型数据库"。 3.PostgreSQL具有极高的可靠性&#xff…

数据结构--并查集的进一步优化

数据结构–并查集的进一步优化 Find操作的优化(压缩路径) 压缩路径 − − F i n d 操作&#xff0c;先找到根节点&#xff0c;再将查找路径上所有结点都挂到根结点下 \color{red}压缩路径 -- Find操作&#xff0c;先找到根节点&#xff0c;再将查找路径上所有结点都挂到根结点…

第二十三章:存储引擎

第二十三章&#xff1a;存储引擎 ​ 为了管理方便&#xff0c;人们把连接管理、查询缓存、语法解析、查询优化这些并不设计真实数据存储的功能划分为MySQL server的功能&#xff0c;把真实存取数据的功能划分为存储引擎的功能。所以在MySQL server完成了查询优化后&#xff0c…

各种好看的css效果收集

CSS动画特效-多种方案实现CSS光束扫过&#xff0c;扫光特效&#xff0c;ae文字过光效果&#xff0c;光效移动效果 一个集合180种免费的线性渐变网站&#xff0c;可在任何网站使用您不仅可以复制渐变的原生CSS颜色代码&#xff0c;还可以查看下载每个优质的渐变图片。 链接&…

多线程——python进阶知识

多线程与多进程的区别 多线程是单个内核通过锁的手段实现同一时间运行多个程序&#xff0c;在某些情况下可以提升总体的运行效率。同时为了防止多个线程在对同一数据进行修改时导致的不可预测的后果&#xff0c;需要借助锁、队列等保证进程的同步。 多进程是多个内核执行多个…

(赠书活动第4期)编译语言的思考过程

面向对象编程&#xff08;Object-Oriented Programming&#xff0c;简称OOP&#xff09;是一种广泛应用于编程领域的编程范式&#xff0c;对于前端和后端开发都具有重要意义。在这篇说明中&#xff0c;我们将探讨面向对象编程对于前端和后端开发的重要性&#xff0c;并探讨其优…

【Linux指令集】---mv指令(超详细)

个人主页&#xff1a;平行线也会相交 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【Linux专栏】&#x1f388; 本专栏旨在分享学习Linux的一点学习心得&#xff0c;欢迎大家在评论区讨论&#x1f48c; 演示环境&#xff1…

高效工作:ADManager Plus的利器

在当今快节奏的商业环境中&#xff0c;高效的工作是成功的关键。对于IT管理员来说&#xff0c;管理和维护Active Directory&#xff08;AD&#xff09;环境是一项重要的任务。然而&#xff0c;手动处理繁琐的AD管理任务可能会占用大量的时间和精力&#xff0c;影响工作效率。为…

可使用Linux 测试IP和端口是否能访问,查看返回状态码

一、 使用wget判断 wget是linux下的下载工具&#xff0c;需要先安装. 用法: wget ip:port wget ip:port连接存在的端口 二、使用telnet判断 telnet是windows标准服务&#xff0c;可以直接用&#xff1b;如果是linux机器&#xff0c;需要安装telnet. 用法: telnet ip port…

【Elasticsearch】RestAPI

目录 4.RestAPI 4.0.导入Demo工程 4.0.1.导入数据 4.0.2.导入项目 4.0.3.mapping映射分析 4.0.4.初始化RestClient 4.1.创建索引库 4.1.1.代码解读 4.1.2.完整示例 4.2.删除索引库 4.3.判断索引库是否存在 4.4.总结 4.RestAPI ES官方提供了各种不同语言的客户端&…

基于vscode的ros开发

Part1前言 ROS&#xff08;机器人操作系统&#xff09;是一个开源的机器人软件平台&#xff0c;旨在提供一套通用的工具和库&#xff0c;帮助开发人员创建机器人应用程序。ROS提供了用于构建机器人系统的库、工具、驱动程序、通信协议和软件包管理系统。 以下是ROS的一些主要特…

第二十章:MySQL的数据目录

第二十章&#xff1a;MySQL的数据目录 20.1&#xff1a;MySQL8的主要目录结构 安装好mysql后&#xff0c;可以使用如下命令查看含有相关mysql的文件。 find / -name mysql # 数据库文件的存放路径 # /var/lib/mysql# mysql数据库文件 # /var/lib/mysql/mysql # /etc/logrota…

解决Material UI引入button按钮后英文字符被自动转化成全大写

目录 前言一、解决方法总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 环境&#xff1a; angularjs 1.4.3 material ui 1.1.4 问题描述 在引入<button>按钮的时候&#xff0c;带入了material 的按钮样式&#xff0c;导致了问题&#xff…

【Linux】- 常用指令和运行级别

运行级别 1.1&#x1f69e;指定运行级别1.2&#x1f68a;帮助指令1.3&#x1f694;文件目录类指令2.1 **ls 指令**2.2 **cd 指令**2.3 **mkdir 指令**2.4 **rmdir 指令**3.1 **touch 指令**3.2 **cp 指令**3.3 **rm 指令**3.4 **mv 指令**4.1 **cat 指令**4.2 **more 指令**4.3…

[QT编程系列-2]:C++图形用户界面编程,QT框架快速入门培训 - 1- 预备知识

目录 概述 1. 前置条件 1.1 C 1.2 图形界面 1.3 图形程序集成开发环境 1.4 图形程序开发框架 1.5 跨平台特性 1.6 QT快速感知 1.6.1 QT的典型应用 1.6.2 QT的特点 1.6.3 QT跨平台集成开发环境 1.6.4 QT是一种UI开发框架 1.6.5 QT的主要函数库 概述 1. 前置条件 学习…

解析三防平板在工业自动化的应用价值

三防平板作为一种具有出色性能和特殊设计的电子设备&#xff0c;为工业自动化领域带来了巨大的应用价值。采用英特尔凌动四核处理器&#xff0c;三防平板具备先进的技术与处理能力。同时配备Window 10操作系统&#xff0c;这款三防平板能够轻松执行多种任务指令。此外&#xff…

高数笔记3(第一章函数 极限 连续-极限的计算1)

目录 三、极限的计算概括&#xff08;1&#xff09;利用四则运算法则求极限常用的结论&#xff08;***&#xff09;未定式的分类以及做法&#xff08;***&#xff09;**例33 &#xff08;93 数三&#xff09;注意负无穷** &#xff08;2&#xff09;利用两个重要极限求极限&…