C语言——函数指针与指针函数

一、函数指针

        1、定义

        顾名思义,函数指针就是函数的指针。它是一个指针,属于一个数据类型,其指向一个函数。如定义一个函数,其入口地址就是这个函数的指针,是个常量,可以用该常量给函数指针类型的变量赋值,如下:

void (*p_fun)();//定义函数指针变量
void fun()
{
//空函数;
}p_fun = fun;//给变量赋值
p_fun = &fun;//这样的写法也认可
使用函数指针就在于便于分层设计、利于系统抽象、降低耦合度以及使接口与实现分开。

        2、使用例子

        如下,函数指针的简单使用,

#include <stdio.h>
int sum(int a,int b)
{return a+b;
}
int main()
{int sum1,sum2;int (*fun)(int x,int y);fun = sum;sum1 = (*fun)(1,2);sum2 = sum(1,2);printf("%d,%d",sum1,sum2);return 0;
}

其执行的结果为:

3,3

可以看出其结果一致,在使用函数指针时,通过用(*fun)取出存在这个地址上的函数,然后调用它。

        上面的例子比较简单,再看看下面的使用:

void Fun()
{printf("hello world!\n");
}int main()
{void (*p)();*(int*)&p=(int)Fun;(*p) ();return 0;
}

首先,void (*p)();这句代码定义了一个指针变量p,其指向一个函数,这个函数的参数和返回值都是void。&p是求指针变量的地址(即地址的地址),(int *)&p表示将地址强制转换成指向int类型数据的指针,*(int*)&p=(int)Fun则表示,将函数的入口地址赋值给指针变量p。之后便于上面例子相同了。

        下面,再来看一个比较复杂的,其在单片机的固件中使用较多,

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

这是《C Traps and Pitfalls》这本经典的书中的一个例子。下面来逐步分析,第一步:void(*) (),可以明白这是一个函数指针类型。这个函数没有参数,没有返回值。第二步:(void(*) ())0,这是将 0 强制转换为函数指针类型,0 是一个地址,也就是说一个函数存在首地址为 0 的一段区域内。第三步:(*(void(*) ())0),这是取 0 地址开始的一段内存里面的内容,其内容就是保存在首地址为 0 的一段区域内的函数。第四步:(*(void(*) ())0)(),这是函数调用。好像还是很简单是吧,上面的例子再改写改写:(*(char**(*) (char **,char **))0) ( char **,char **);看不懂了就是参考这里

        3、函数指针数组

        欲将多个函数指针在内存中连续的放在一起,就可以定义为一个函数指针数组。如下:

char * (*p_fun[3])(char * p);
它是一个数组,数组名为 p_fun ,数组内存储了 3 个指向函数的指针。这些指针指向一些返回值类型为指向字符的指针、参数为一个指向字符的指针的函数。但这是一个指针数组,是数组类型。
一般使用方法如下:
void fun1(void)
{printf("1\n");
}
void fun2(void)
{printf("2\n");
}
void fun3(void)
{printf("3\n");
}
int main()
{void (*pf[3])();pf[0] = fun1; // 可以直接用函数名pf[1] = &fun2; // 可以用函数名加上取地址符pf[2] = &fun3;pf[0]();pf[1]();pf[2]();return 0;
}

二、指针函数

        指针函数, 即返回值为指针的函数, 实质上是一个函数。如:

int * fun(void);
char * fun(int a);
void * fun(char * a,char * b);

所谓的指针函数也没什么特别的,和普通函数对比不过就是其返回了一个指针(即地址值)而已。

例如,求最大值函数(指针作为函数的返回值)

#include <stdio.h>
int *max(int *p1, int *p2) 
{if(*p1 > *p2)return p1;else return p2;
}
int main()
{int *p, a, b;a = 1; b = 2;p = max(&a, &b);printf("%d\n", *p);return 0;
}


 

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

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

相关文章

Spark-RDD-依赖关系详解

Spark概述 Spark-RDD概述 Spark-RDD-依赖关系 在Apache Spark中&#xff0c;RDD&#xff08;Resilient Distributed Dataset&#xff09;是一种基本的抽象数据结构&#xff0c;代表了分布式的、不可变的数据集。 RDD之间的依赖关系在Spark中非常重要&#xff0c;因为它们决定了…

汇编语言(一)

寄存器&#xff1a;cpu中可以储存数据的器件&#xff08;AX&#xff0c;BX&#xff09; 汇编语言的组成&#xff1a;1.汇编指令 2.伪指令 3.其他符号 存储器&#xff1a;cpu&#xff0c;传入指令和数据&#xff0c;加以运算。&#xff08;内存&#xff09; 指令和数据&#…

DBAPI怎么进行数据格式转换

DBAPI如何进行数据格式的转换 假设现在有个API&#xff0c;根据学生id查询学生信息&#xff0c;访问API查看数据格式如下 {"data":[{"name":"Michale","phone_number":null,"id":77,"age":55}],"msg"…

【java程序设计期末复习】chapter1 java入门

java入门 java的特点 &#xff08;1&#xff09;简单 Java要比C简单&#xff0c;C中许多容易混淆的概念&#xff0c;或者被Java弃之不用了&#xff0c;或者以一种更清楚更容易理解的方式实现 &#xff08;2&#xff09;面向对象 Java是面向对象的编程语言 &#xff08;3&…

【一站式学会Kotlin】第九节:inline 内联函数

作者介绍: 百度资深Android工程师T6,在百度任职7年半。 目前:成立赵小灰代码工作室,欢迎大家找我交流Android、微信小程序、鸿蒙项目。= 一:通俗易懂的人工智能教程:https://www.captainbed.cn/nefu/ 点一下,打开新世界的大门。 二:【一站式学会Kotlin】免费领取:作者…

如何关闭或者减少屏蔽 CloudFlare 的真人检测

经常浏览境外网站的应该常碰到一个真人检测的提示(如下图所示)。最近,明月就收到了一个知乎上的付费咨询:问我如何去掉这个提示,由此明月也特别的研究了一下这个“真人检测”,这算是 CloudFlare 的一个特色了,基本上大家看到站点访问有这个提示的几乎都是用了 CloudFlar…

xjoi题库一级1-10段题解(c语言版)

xjoi题库一级一段 xjoi题库一级二段 xjoi题库一级三段 xjoi题库一级四段 xjoi题库一级五段

比特币的理论上限是多少个?

标签: 比特币的理论上限; 已经挖出多少个比特币; 问题:比特币的理论上限是多少个?截至2023年10月,已经挖出多少个比特币出来了? 比特币的理论上限 比特币的设计者中本聪在比特币协议中设定了比特币的最大供应量为 21,000,000(2100万)个。这个上限是通过一种称为“减…

CSS3优秀动画代码示例

目录 旋转立方体悬停效果动画路径动画纯CSS进度条文字打字机效果3D翻转卡片SVG路径跟随动画SVG心跳动画旋转文字手风琴效果

【同构字符串】python

思路&#xff1a; 先记录同一个值出现的次数&#xff0c;再将字典中的值取出&#xff0c;比较2个列表即可 代码&#xff1a; class Solution:def isIsomorphic(self, s: str, t: str) -> bool:dit1dict()dit2dict()for i in range(len(s)):if s[i] not in dit1:dit1[s[i…

01.并发编程简介

1 什么是并发编程 所谓并发编程是指在一台处理器上“同时”处理多个任务。并发是在同一实体上的多个事件。多个事件在同一时间间隔发生。 2 为什么我们要学习并发编程&#xff1f; 最直白的原因就是因为面试需要&#xff0c;大厂的 Java 岗的并发编程能力属于标配。 而在非大厂…

Stanford斯坦福 CS 224R: 深度强化学习 (6)

CS 224R 离线强化学习&#xff1a;第二部分 课程介绍请看第一节内容 课程回顾 离线强化学习、数据约束和保守性 离线强化学习旨在利用离线数据&#xff0c;重复使用离线数据是有益的。其关键挑战是由于 π β \pi_\beta πβ​ 和 π θ \pi_\theta πθ​ 之间的偏移导致…

CentOS 7.9部署宝塔面板超详细

CentOS7 部署宝塔面板 Linux的宝塔面板搭建起来非常轻松&#xff0c;也可以用一句话来形容&#xff0c;如果喝水一样简单&#xff0c;只需一条命令剩下的交给时间&#xff0c;几分钟就能部署好&#xff0c;然后就可以直接进行登录&#xff0c;直接可以安装LNMP、LAMP平台&…

【2024】LeetCode HOT 100——动态规划

目录 1. 爬楼梯1.1 C++实现1.2 Python实现1.3 时空分析2. 杨辉三角2.1 C++实现2.2 Python实现2.3 时空分析3. 打家劫舍3.1 C++实现3.2 Python实现3.3 时空分析4. 完全平方数4.1 C++实现4.2 Python实现<

海外仓储管理系统:提升效率,标准化海外仓管理,科技赋能业务

海外仓作为跨境物流的关键一环&#xff0c;完全可以说海外仓的效率直接决定了后续物流的整体运作效率。 对于海外仓而言&#xff0c;一套高效&#xff0c;易用的海外仓储系统&#xff0c;无疑将成为提升企业竞争力的重要工具&#xff0c;帮助海外仓实现从野蛮生长到标准化管理…

2024.05.26 第 399 场周赛

Leetcode 第 399 场周赛 优质数对的总数 I Leetcode 优质数对的总数 I 给你两个整数数组 nums1 和 nums2&#xff0c;长度分别为 n 和 m。同时给你一个正整数 k。 如果 nums1[i] 可以被 nums2[j] * k 整除&#xff0c;则称数对 (i, j) 为 优质数对&#xff08;0 < i < n…

MT3040 矩形覆盖

代码&#xff1a; #include <bits/stdc.h> using namespace std; typedef long long ll; const int N 3e5 10; int n, ans, d, w; stack<int> s; // 单调栈 // 如果楼高度类似121&#xff08;凸&#xff0c;两边相等&#xff0c;中间比两边的大&#xff09;&…

微服务:Nacos简介以及安装部署

一、前言 Nacos&#xff08;全称Dynamic Naming and Configuration Service&#xff09;是一个由阿里巴巴集团开发并开源的分布式服务发现和配置管理平台。它是构建以“服务”为中心的现代应用架构&#xff08;如微服务范式、云原生范式&#xff09;的服务基础设施。 Nacos架构…

设计模式深度解析:分布式与中心化,IT界两大巨头“华山论剑”

​&#x1f308; 个人主页&#xff1a;danci_ &#x1f525; 系列专栏&#xff1a;《设计模式》《MYSQL应用》 &#x1f4aa;&#x1f3fb; 制定明确可量化的目标&#xff0c;坚持默默的做事。 ✨IT界的两大巨头交锋✨ &#x1f44b; 在IT界的广阔天地中&#xff0c;有两座…

微火问答:全域外卖和本地生活服务是同个项目吗?

当前&#xff0c;本地生活赛道火爆程度不断升级&#xff0c;作为其主要板块之一的团购外卖也持续迸发出新的活力。而全域运营的出现无疑是给团购外卖这把正在熊熊燃烧的烈火&#xff0c;又添了一把新柴&#xff01; 所谓全域运营&#xff0c;简单来说&#xff0c;就是指所有领…