函数指针,指针函数,函数指针数组

这是一个群友发的笔试题目,里面涉及的东西也比较有意思。

直接看代码

void (*f[])(char *)

这个是个什么东西?

我们先看看下面的东西

函数指针和指针函数的定义

我们看个代码

int *func(int a,int b)

我们之前说过运算符的优先级,「 」  的优先级低于「  」

由于「 * 」的优先级低于「 () 」的优先级,因而func首先和后面的「 () 」结合,也就意味着,func是一个函数。即:

int *(func)(int a,int b)

然后这个函数的返回值的类型是「  int * 」 即:指向int类型的指针

然后我们这样修改上面的代码

int (*func)(int a,int b)

(*func) 」说明func是一个指针,然后后面跟着「()」说明这个指针指向一个函数,即指向函数的指针。

所以

函数指针: 首先是一个指针,这个指针指向一个函数

指针函数:首先是一个函数,这个函数的返回值一个指针

用typedef声明一个函数指针

我们声明一个函数指针,正常方法是

int (*pfunc)(int a,int b)

当我们命名很多个函数指针的时候,用上面的方法显得非常不方便,所以我们可以这样做

typedef int (*PF) (int a,intb)
PF pfunc;

例程:

#include "stdio.h"typedef int(*PF)(int, int);int add(int a, int b)
{return a   b;
}int reduce(int a, int b)
{return a - b;
}int main()
{PF pfunc = NULL;pfunc = add;printf("add:%d\n",pfunc(3, 4));pfunc = reduce;printf("reduce:%d\n", pfunc(3, 4));/*getchar是用VS编写方便查看输出*/getchar();return 0;
}

再说回上面的那个题目

void (*f[])(char *)

f 是个什么鬼东西了?

[] 的优先级 比 *的优先级高,所以 f首先是修饰了数组,然后跟后面的 *组合,就说明这个数组里面住的都是 指针,这些指针是什么呢,再出来看看就看到了,这个指针是 一个函数,这个函数的 参数是 char *返回值是void

示例代码

#include void (*f[3])(char *);void efunction(char * s)
{printf("%s\n",s);
}int main()
{f[0] = efunction;//void (*f[])(char *) = {efunction}; (*f[0])("hello code");return 0;
}

代码输出

hello code--------------------------------
Process exited after 0.08441 seconds with return value 0
请按任意键继续. . .

函数指针在项目总的实际应用

这是我的android项目hal部分的代码,这部分代码用到的是函数指针,通过name来调用不同的函数。

懂了这些,我们就可以看懂别人的代码了

我们有时候看别人的代码时候,经常是一面懵逼,比如下面这个void (*p)(); 还有这个(*(void(*) ())0)();

我记得我在以前的文章里面有谈到一个右左原则,从p开始看,往右走直到遇到)再往左走遇到(,(*p)我们就可以看出p是一个指针,继续分析往右走,遇到(),说明p指向一个(void)的函数,往左走,知道p指向的函数返回值是void

ok,看下面的例子。

#include "stdio.h"void Function()
{printf("Call    Function!\n");
}int main()
{void(*p)();*(int*)&p = (int)Function;(*p)();getchar();return 0;
}

然后继续分析(*(void(*) ())0)();

  • 1、void (*)()  我们上面分析了这个是一个函数指针,只是把p去掉了而已。

  • 2、把上面的void (*)()PN代替,上面的表达式变成(*(PN)0)();PN后面有一个0,这个是让我们咋舌的地方,然后我们向一下 (char)a;这样的表达式,所以*(PN)0就是把0当成一个地址,强制转换为PN类型,用*这个钥匙取出这个地址区域的值。

  • 3、把(*(PN)0)()替换成PM,原来的表达式变成PM(),这样大家看起来比较容易了吧,就是正常的函数调用。

给个例子自己去参透一下

#include 
#include char * fun1(char * p)
{printf("%s\n", p);return p;
}char * fun2(char * p)
{printf("%s\n", p);return p;
}char * fun3(char * p)
{printf("%s\n", p);return p;
}int main()
{char * (*pf[3])(char * p);pf[0] = fun1; // 可以直接用函数名pf[1] = &fun2; // 可以用函数名加上取地址符pf[2] = &fun3;pf[0]("fun1");pf[0]("fun2");pf[0]("fun3");getchar();return 0;
}

声明:

本文于网络整理,版权归原作者所有,如来源信息有误或侵犯权益,请联系我们删除或授权事宜。

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

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

相关文章

win10默认浏览器不显示谷歌浏览器_win10系统谷歌浏览器怎么用不了?谷歌浏览器打不开网页的解决方法...

刚接触谷歌Chrome浏览器的时候,会觉得这个软件的操作界面非常地陌生,界面简洁得不像话。win10系统电脑下载好Google Chrome既谷歌浏览器后,发现打不开网页,谷歌浏览器怎么用不了?其实通过设置搜索引擎就可以打开了&…

畅享10e会有鸿蒙吗,功能虽小作用很大 华为畅享10e隐藏功能大揭秘

原标题:功能虽小作用很大 华为畅享10e隐藏功能大揭秘如今使用手机游戏、观影、听音乐、刷短视频、拍照等多种多样的娱乐方式,充斥着年轻人生活之中。作为年轻用户娱乐的重要载体,现在的手机不仅硬件强大,在软件功能上方面也取得了突破性进展,不仅仅是高端机,甚至千元…

jax-ws和jax-rs_使用JAX-RS和Spring构建HATEOAS API

jax-ws和jax-rs在我以前的博客文章中,我展示了如何使用Spring Boot配置Jersey多么容易。 我对Spring Boot和Jersey的探索并未结束,我研究了在Spring Boot应用程序中将Spring HATEOAS与Jersey一起使用的可能性。 Spring HATEOS允许创建遵循HATEOAS原理的R…

C this指针的理解和作用

C 程序到 C 程序的翻译 要想理解 C 的 this 指针,我们可以先把下面的 C 代码转换成 C 代码:C 语言是没有类定义 class 关键词,但是有跟 class 类似的定义,那就是 struct 结构体。m_price 变量是 Car 类的成员变量,那…

yolov3安卓实现_YOLOv3 的 TensorFlow 实现,GitHub 完整源码解析

来自华盛顿大学的 Joseph Redmon 和 Ali Farhadi 提出的YOLOv3 通过在 YOLO 中加入设计细节的变化,这个新模型在取得相当准确率的情况下实现了检测速度的很大提升,一般它比 R-CNN 快 1000 倍、比 Fast R-CNN 快 100 倍。这里附上 YOLOv3 的论文地址&…

C++ inline 函数简介

1.inline 函数简介inline 函数由 inline 关键字定义,引入 inline 函数的主要原因是用它替代 C 中复杂易错不易维护的宏函数。2.编译器对 inline 函数的处理办法编译器在编译阶段完成对 inline 函数的处理,即对 inline 函数的调用替换为函数的本体。但 in…

intellij ide_UltraESB的首选IDE – IntelliJ IDEA

intellij ide在AdroitLogic,我们长期以来一直在使用IntelliJ IDEA进行开发。 它是Java和相关语言/技术的最佳IDE(它可能也是许多其他语言的选择,但我的经验主要是Java和相关技术)。 Groovy和IDEA的Grails的集成很棒。 通过自动发…

install npm 到某个文件下执行_如何将npm安装到指定目录?

从npm版本3.8.6开始,您可以使用npm install --prefix ./install/here 安装在指定的目录中。node_modules即使node_modules较高层次结构中已存在目录,NPM 也会自动创建文件夹。您还可以package.json在当前目录中拥有a ,然后使用以下--prefix选…

android 启动界面位置,android 修改默认启动项launcher(一)

需求:不去掉系统自带launcher的前提下,默认启动指定应用作为launcher现象:应用中带有属性"android.intent.category.HOME",开机会弹出选择界面思路:跳过选择界面,直接选中要启动的launcher并直接…

C++抽象类

概念在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是用来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。抽象类往往用来表征对问题领域进行分…

iview select选中值取值_iView的Select选择框

目录在此先列出解决了那些问题,以防读者看完了没有用处:1、示例,最基础的使用方法2、传参,传多个值的方式3、默认值4、清空重置无效5、可搜索的用法及如何限制搜索字符长度一、示例html:{{item.name}}js:data: {formSend: {name: …

tibco_TIBCO产品的微服务和DevOps

tibco大家都在谈论微服务 ,这些天。 您可以在数百篇文章和博客文章中读到很多有关微服务的信息。 马丁福勒 ( Martin Fowler )的文章是一个很好的起点,该文章引发了有关这种新架构概念的大量讨论。 另一个不错的资源是独立于供应…

android 冰箱 活动,Android活动的使用

创建第一个应用:步骤一:1、Activity :一个页面2、Layout :页面布局3、Res:页面内的资源注意:所有的Activity都是继承与android.app.activity类,通过override实现。简单理解Activity 代表一个用户所能看到的…

C atoi函数

作用atoi()函数将数字格式的字符串转换为整数类型。例如,将字符串1253124127转换成数字1253124127。注意首要注意atoi函数可以转化如下这种字符串1fdafhdjfhkas关于参数的注意事项,atoi()函数的参数是要转换的字符串。该字符串的格式为[空格][符号][数字…

python lock_python多线程Lock和RLock的区别

python多线程Lock和RLock的区别1. 两种锁的不同1.1 定义为了确保对共享资源的访问,python提供了两种锁,一个是上一篇提到的Lock,还有一个就是RLock,他们的区别在于:Lock是可用的最低级别的同步指令,一个线程…

开式蓄冷罐与闭式蓄冷罐_一罐将其全部统治:Arquillian + Java 8

开式蓄冷罐与闭式蓄冷罐借助Java 8 ,已实现了许多新的语言改进,以简化开发人员的生活。 在我看来, Java 8的最大优点之一是,在某些情况下,已开发的代码看起来比使用以前的方法更漂亮,我指的是Lambdas和Meth…

C 预处理指令

C 预处理指令C语言、C 语言的预处理器。用于在编译器处理程序之前预扫描源代码,完成头文件的包含, 宏扩展, 条件编译, 行控制(line control)等操作编译的四个阶段C语言标准规定,预处理是指前4个编译阶段(phases of tra…

将html代码转换为dom,将HTML字符转换为DOM节点并动态添加到文档中

将HTML字符转换为DOM节点并动态添加到文档中将字符串动态转换为DOM节点,在开发中经常遇到,尤其在模板引擎中更是不可或缺的技术。字符串转换为DOM节点本身并不难,本篇文章主要涉及两个主题:1 字符串转换为HTML DOM节点的基本方法及…

python 的csr_python的高级数组之稀疏矩阵

稀疏矩阵的定义:具有少量非零项的矩阵(在矩阵中,若数值0的元素数目远多于非0元素的数目,并且非0元素分布没有规律时,)则称该矩阵为稀疏矩阵;相反,为稠密矩阵。非零元素的总数比上矩阵所有元素的总数为矩阵的…

通过Spring集成进行消息处理

Spring Integration提供了Spring框架的扩展,以支持著名的企业集成模式。 它在基于Spring的应用程序中启用轻量级消息传递,并支持与外部系统的集成。 Spring Integration的最重要目标之一是为构建可维护且可测试的企业集成解决方案提供一个简单的模型。 …