C语言---函数指针

2023-11-13

前言

(1)函数指针,顾名思义,就说函数的指针。

(2)我们学习Linux的时候,经常能够看到使用一个结构体,结构体中很多个成员,我们给这些成员赋于函数名。这样非常方便我们管理一个设备文件。

(3)本文将会详细介绍函数指针。

函数指针介绍

函数指针原型

(1)函数指针的原型是不固定的,他根据你的原函数类型所决定。什么意思呢?看代码(2)根据代码,我们发现其实这个函数指针的定义,和所指向的函数是一样的(也就是说,函数指针p与原函数print是一样的,函数指针a与原函数add是一样的)。最终使用的时候,使用方式和原函数也一样。

(3)这个函数指针我们可以理解为,就是将函数名改了一下,原来是print现在是p,原来是add,现在是a。只不过在定义的时候,需要将print改成(*p),add改成(*a)

(4)这个时候,肯定会有人问为什么这么做呢,直接使用原函数名不香吗?后续会讲

void print(void)
{
	printf("test\n");
}

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

int main()
{
    //我们对比这两个函数指针,发现他们的是根据所指向的函数是一样的
    //我们可以理解为,就是讲函数名改了一下,原来是print现在是p,原来是add,现在是a。
	void(*p)(void) = print;
	int(*a)(int, int) = add;
	p();
	printf("%d\n",a(1, 2));
	return 0;
}

函数指针使用的时候不需要*

 我们看到上面的代码,发现函数指针在定义的时候,需要写成(*p),但是在使用的时候,直接使用p了。我们可以加上*吗?可以的,不过加上之后没用,可以忽略

	//下面的结果是一样的
    p();
	(*p)();
	printf("%d\n", a(1, 2));
	printf("%d\n", (*a)(1, 2));

函数指针加深理解

题目一

(1)我们来看下面这个是什么意思。首先,我们从左到右理解,首先是第一个大括号,不用管。之后我们看到*里面是一个(),因为()优先级最高,所以先括号里面的内容。看到括号里面的内容,有没有想到什么?对的,函数指针!这就是一个函数指针。

(2)现在我们可以将下面这个改成(*(函数指针)0)()了。这个时候,我们需要思考了,这个是什么玩意了。我们再次回到上面的函数指针不需要*的内容去。发现什么了吗,  p()==(*p)(),而p又是一个函数指针。

(3)那么现在我们是不是也可以这么理解,我们是在将一个地址为0的函数指针进行调用呢?而(函数指针)0就是将0强制类型转换为一个函数指针。

( *(void (*)())0 )();

题目二

(1)看了上面这个代码,现在这个是不是非常好理解了。

(2)先看将他理解为一个void(*signal)(int),xxx我们先不管,从大体上来看,他就是一个函数指针。而signal的内容,也能够一眼看出来,也是一个函数指针。他的第二个参数也是一个函数指针。

void (*signal(int , void(*)(int)))(int);

(3)这个函数如何简化呢?typedef就是很好的重命名方式。

//错误写法
typedef void(*)(void) p;

//正确写法
typedef void(*p)(void); //将void(*)(void)函数指针类型冲命名为p

//最终简化结果
void (*signal(int , void(*)(int)))(int) == \
p signal(int, p);

函数指针实操

实操一

我们下面模仿一个计算机的功能。输入对应的数字执行相应功能。我们对比不使用函数指针和使用函数指针,是不是发现使用函数指针之后,代码可读性和简洁程度高了很多。


#include <stdio.h>
int add(int a, int b)
{
	return a + b;
}
int sub(int a, int b)
{
	return a - b;
}
int mul(int a, int b)
{
	return a*b;
}
int div(int a, int b)
{
	return a / b;
}

/******* 不使用函数指针  *******/
int main()
{
	int x, y;
	int input = 1;
	int ret = 0;
	do
	{
		printf("*************************\n");
		printf(" 1:add 2:sub \n");
		printf(" 3:mul 4:div \n");
		printf("*************************\n");
		printf("请选择:");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("输入操作数:");
			scanf("%d %d", &x, &y);
			ret = add(x, y);
			printf("ret = %d\n", ret);
			break;
		case 2:
			printf("输入操作数:");
			scanf("%d %d", &x, &y);
			ret = sub(x, y);
			printf("ret = %d\n", ret);
			break;
		case 3:
			printf("输入操作数:");
			scanf("%d %d", &x, &y);
			ret = mul(x, y);
			printf("ret = %d\n", ret);
			break;
		case 4:
			printf("输入操作数:");
			scanf("%d %d", &x, &y);
			ret = div(x, y);
			printf("ret = %d\n", ret);
			break;
		case 0:
			printf("退出程序\n");
			break;
		default:
			printf("选择错误\n");
			break;
		}
	} while (input);
	return 0;
}


/******* 使用函数指针  *******/
int main()
{
	int x, y;
	int input = 1;
	int ret = 0;
	int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表
	while (input)
	{
		printf("*************************\n");
		printf(" 1:add 2:sub \n");
		printf(" 3:mul 4:div \n");
		printf("*************************\n");
		printf("请选择:");
		scanf("%d", &input);
		if ((input <= 4 && input >= 1))
		{
			printf("输入操作数:");
			scanf("%d %d", &x, &y);
			ret = (*p[input])(x, y);
		}
		else
			printf("输入有误\n");
		printf("ret = %d\n", ret);
	}
	return 0;
}


实操二

我们在编写Linux驱动程序的时候,总是能够看到file_operations结构体,其中每个变量都说一个函数指针。我们只需要调用这个结构体中的变量,就可以直接操作到对应的驱动程序。这样在庞大的Linux系统中,会非常方便。

static const struct file_operations  hello_drv = {
    .owner      = THIS_MODULE,
	.read		= hello_read,   //hello_read为函数指针
	.write		= hello_write,  //hello_write为函数指针
	.open		= hello_open,   //hello_open为函数指针
    .release    = hello_release //hello_release为函数指针
};

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言---函数指针 的相关文章

随机推荐

  • 题目描述已知矩形的长和宽,计算其周长和面积。

    1010 矩形的周长和面积 1级 时间限制 1 Sec 内存限制 128 MB 提交 777 解决 442 提交 状态 讨论版 命题人 admin 题目描述 已知矩形的长和宽 计算其周长和面积 输入 仅一行 用空格隔开的两个整数 表示矩形的
  • 如何使用apt-cache搜索来查找软件包?

    这篇已经讲得很详细了 留言记录 如何使用apt cache搜索来查找软件包 腾讯云开发者社区 腾讯云
  • EJB分布式应用中需注意的问题

    1 EJB事务 EJB和spring事务都只能对RuntimeException进行事务回滚 所以要进行事务回滚的BO要throw RMSSysException而不是RMSAppException 现在的做法是在生成EJB代码时将RmsA
  • 2019.04.08—Java 中字母汉字占几个字节

    今天在做回顾的时候看到的问题 为什么两个运行的结果不一样呢 1 弄清java中的字节与字符 问题 在java中 一个字符等于多少字节 或者更详细的问 在java中 一个英文字符等于多少字节 一个中文字符等于多少字节 答案 Java采用uni
  • C++与Python混编——使用Pyhon扩展C++程序(1)

    在正式开始python与C 之间混合编程前 我们先从python官方文档中查看相关的资料 https docs python org 3 6 extending embedding html 本文及接下来相关博文 均已 vs2017 pyt
  • 命令行批量缩小图片尺寸

    最近要邮件发一批图片 可是图片文件总容量太大 每个都有2M多 需要缩小一下 就上网找了一下批量缩放图片大小的工具发现了Imagemgick这个好东西 Imagemgick是一个可以通过命令行对文件进行处理的程序 支持linux Mac OS
  • 常用shell命令

    查找字符串 grep r struct event base n 在当前目录查找字符串 找到后返回文件和对应的行 统计文件行数 字节 字数 wc命令 选项 l c w分别统计行数 字节 字数 可统计多文件 但不能统计目录 wc c main
  • 结构化程序设计:输入一个正整数(不超过5位数),输出由该数的各位能表示的最大数和最小数。

    结构化程序设计 输入一个正整数 不超过5位数 输出由该数的各位能表示的最大数和最小数 思路 代码 分析 1 分离x各位数到数组a中 2 对数组a进行排序 3 根据乘权求和算法 对已排好序的数组a分别从大到小和从小到大计算最大最小值 思路 首
  • ytht & infomall.cn

    为什么无法访问三角地版 近来有很多公众网用户无法访问三角地版 甚至一访问三角地版就会导致 IP 被自动封禁 从而无法继续连接一塌糊涂 为什么会出现这种奇怪的现象呢 我们的技术人员经过研究发现 只要您浏览包含有 triangle 字样的链接
  • 3D 贴图丢失的检测以及解决办法大全

    现在大部分设计师建好模型直接会丢在网上渲染 渲染完成后直接可以本地电脑下载结果 这样可以给行内设计师解决大部分渲图时间 但平时我们渲图会出现贴图丢失的情况 这到底是怎么回事 应该怎么解决这个问题呢 今天我做了个详细的归档 可以检测下贴图丢失
  • office全家桶_5个免费实用的Office学习网站,请马住

    我经常收到后台的私信或者现实生活周边的朋友咨询 有什么免费实用的Office学习教程或者网站 这倒是个大需求 基本只要涉及点到需要处理文字 数据等的工作都会要求会一点Office办公软件 当然了 岗位的不太所需要的Office熟练程度会有不
  • Linux :: 权限篇【2】:详解文件操作权限表示方式!字符表示法 及 八进制表示法说明!

    系列文章说明 前言 本篇是 Linux 基本操作篇章的内容 笔者使用的环境是基于腾讯云服务器 CentOS 7 6 64bit 学习集推荐 C 入门到入土 学习合集 Linux 从命令到网络再到内核 学习合集 文章目录 系列文章说明 前言
  • 面向对象设计模式

    文章目录 一 创建型设计模式 1 1 单例 Singleton 1 2 原型 Prototype 1 3 工厂 Factory 1 3 1 简单工厂 1 3 2 工厂方法 1 3 3 抽象工厂 1 4 建造者 Builder 二 结构型设计
  • vue判断值是否为空以及弹出提示框

    if this checkedProjects length 0 alert 该项不能为空
  • xp系统sql服务器怎么找,SQL文件在winxp系统下怎么打开

    很多用户不知道SQL文件是什么 SQL文件怎么打开 我们存储数据时候经常会遇到SQL文件 如果你不知道WinXP系统SQL文件是什么以及怎么打开的话 那就赶紧看看小编整理的以下文章内容吧 SQL文件是什么 学习编程的同学可能都知道SQL是一
  • CTF_WEB(习题)

    一 bugku web cookie欺骗 https ctf bugku com challenges detail id 87 html 地址栏filename一看为base64 解密为keys php 尝试index php加密为bas
  • vue的请求封装和api接口的封装

    1 请求封装 1 创建utils文件夹 2 在此文件夹创建http js文件 3 在此文件夹引入axios import axios from axios 4 创建一个新的请求实例 const instance axios create b
  • web面试必问的题

    1 Vue双向数据绑定 2 虚拟dom和diff算法 3 组件通信 4 Vuex 5 Vue router 路由原理 路由守卫 路由传参 6 Vue声明周期 7 自定义指令 自定义过滤器 8 自定义组件 9 常用的指令 修饰符 10 vue
  • 动态规划题目总结

    基础题目 剑指 Offer 10 I 斐波那契数列 70 爬楼梯 剑指 Offer II 088 爬楼梯的最少成本 不同路径 II 带障碍 我一定会 卡特兰数 n个节点可以构成多少种搜索二叉树 分割三角形 排队买票 n对括号有多少种合理的表
  • C语言---函数指针

    前言 1 函数指针 顾名思义 就说函数的指针 2 我们学习Linux的时候 经常能够看到使用一个结构体 结构体中很多个成员 我们给这些成员赋于函数名 这样非常方便我们管理一个设备文件 3 本文将会详细介绍函数指针 函数指针介绍 函数指针原型