【C语言】结构体中的函数指针

2023-11-17

目录

一、函数指针是什么?

二、结构体中的函数指针


一、函数指针是什么?

函数指针是指向函数指针变量。 通常我们说的指针变量是指向一个整型、字符型或数组等变量,而函数指针是指向函数。 函数指针可以像一般函数一样,用于调用函数、传递参数。

正确形式:int (*f) ( );

这个声明有两对括号,每对的含义各不相同。第2对括号是函数调用操作符,但第1对括号只起到聚组的作用。它迫使间接访问在函数调用之前进行,使f成为一个函数指针,它所指向的函数返回一个整型值。

容易混淆的地方:int (*f)(); 与 int * f ();

两者看似只相差了一个(),但是在编译器看来却是两种截然不同的情况。

首先我们知道

1、函数名代表这个函数的入口,也就是首地址。

2、符号' * '在不同的情况下有不同的含义。声明时:加上 * 表示这个变量是一个指针。调用时:加上 * 表示访问指针;

#include <stdio.h>
int a = 1;

int * p = &a; 
/* 这里我们分成4个部分来看。左边是3个部分:'int','*','p',右边是'&a。
 * 习惯上我们以 从右往左 的顺序来解读 左边 部分。
 * p :变量p
 * *p :表示p是一个指针,它的值是会被当做地址处理,而不是一个数值
 * int * p : 表示变量p所保存的地址指向的是int类型的数,帮助编译器确定类型
 * &a : 取a的地址
 */   
int main()
{
	printf("*p = %d",*p);
}

输出结果:

结合上面的例子我们来分析一下 int (*f) () 与 int *f ();

二者与int * p一个明显的不同之处就在于f的后面跟了()。这代表它可以输入参数,也就是说 f 表示某个函数的入口。

int * f () 与 int * p类似,代表函数f()的返回值是 指针。这个指针指向int类型。

int (*f) () : 表示 f 是一个指向函数的指针,该函数没有参数并返回 int 值。

int *f () :表示 f 是一个函数,它不接受任何参数,并返回指向 int 值的指针。

  • 函数指针的调用方式 
void test(int);

int main(void)
{
    void (*fp)(int);
    fp=test;    
    (*fp)(9);   //调用方式一:函数指针  

    fp(9);      //调用方式二:函数指示符
    return 0;
}

void test(int a)
{

  printf( "%d\n", a );

}

输出结果:
9
9

这两种形式是等价的。

这是因为在 C/C++ 中总是使用函数指针的形式来调用函数。即使在函数调用中使用的是函数指示符(代表函数类型), 也会被转换为函数指针使用,这就是默认的 function-to-pointer 转换。

尽管二者等价,但个人还是比较推荐用函数指针的形式来调用函数。

二、结构体中的函数指针

函数指针可以作为结构体的成员使用。

以下是使用示例

void Dance_func()

{
  printf("Xiao Ming is dancing!\n");
}

void Sing_func(int i) {
  printf("Xiao Ming Sang %d Songs.\n", i);
}

typedef struct {

  void (*dance)();   //函数指针的正确形式
  void (*sing)(int i);
  //void * sing (int i);  错误形式,无法通过编译
} student;

int main(void)
{

  student Xiao_Ming;
  Xiao_Ming.dance = Dance_func; //对结构体变量的赋值。函数名Dance_func是指针
  Xiao_Ming.dance();            //调用Dance_func()
  Xiao_Ming.sing = Sing_func;   //同上
  Xiao_Ming.sing(3);

  return 0;
}

输出结果:

Xiao Ming is dancing!
Xiao Ming Sang 3 Songs.

注意:

  Xiao_Ming.dance = Dance_func; //对结构体变量的赋值。函数名Dance_func是指针
  Xiao_Ming.dance();            //调用Dance_func()

 二者只相差一个括号,但是意义不同。

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

【C语言】结构体中的函数指针 的相关文章

  • 如何获取正在访问 ASP.NET 应用程序的当前用户?

    为了获取系统中当前登录的用户 我使用以下代码 string opl System Security Principal WindowsIdentity GetCurrent Name ToString 我正在开发一个 ASP NET 应用程
  • 编译时运算符

    有人可以列出 C 中可用的所有编译时运算符吗 C 中有两个运算符 无论操作数如何 它们的结果始终可以在编译时确定 它们是sizeof 1 and 2 当然 其他运算符的许多特殊用途可以在编译时解决 例如标准中列出的那些整数常量表达式 1 与
  • 没有强命名的代码签名是否会让您的应用程序容易被滥用?

    尝试了解authenticode代码签名和强命名 我是否正确地认为 如果我对引用一些 dll 非强命名 的 exe 进行代码签名 恶意用户就可以替换我的 DLL 并以看似由我签名但正在运行的方式分发应用程序他们的代码 假设这是真的 那么您似
  • “构建”构建我的项目,“构建解决方案”则不构建

    我刚刚开始使用VS2010 我有一个较大的解决方案 已从 VS2008 成功迁移 我已将一个名为 Test 的控制台应用程序项目添加到解决方案中 选择构建 gt 构建解决方案不编译新项目 选择构建 gt 构建测试确实构建了项目 在失败的情况
  • 在结构中使用 typedef 枚举并避免类型混合警告

    我正在使用 C99 我的编译器是 IAR Embedded workbench 但我认为这个问题对于其他一些编译器也有效 我有一个 typedef 枚举 其中包含一些项目 并且我向该新类型的结构添加了一个元素 typedef enum fo
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • 不支持将数据直接绑定到存储查询(DbSet、DbQuery、DbSqlQuery)

    正在编码视觉工作室2012并使用实体模型作为我的数据层 但是 当页面尝试加载时 上面提到的标题 我使用 Linq 语句的下拉控件往往会引发未处理的异常 下面是我的代码 using AdventureWorksEntities dw new
  • ASP.NET MVC:这个业务逻辑应该放在哪里?

    我正在开发我的第一个真正的 MVC 应用程序 并尝试遵循一般的 OOP 最佳实践 我正在将控制器中的一些简单业务逻辑重构到我的域模型中 我最近一直在阅读一些内容 很明显我应该将逻辑放在域模型实体类中的某个位置 以避免出现 贫血域模型 反模式
  • 嵌套接口:将 IDictionary> 转换为 IDictionary>?

    我认为投射一个相当简单IDictionary
  • 使用实体框架模型输入安全密钥

    这是我今天的完美想法 Entity Framework 中的强类型 ID 动机 比较 ModelTypeA ID 和 ModelTypeB ID 总是 至少几乎 错误 为什么编译时不处理它 如果您使用每个请求示例 DbContext 那么很
  • 类模板参数推导 - clang 和 gcc 不同

    下面的代码使用 gcc 编译 但不使用 clang 编译 https godbolt org z ttqGuL template
  • HTTPWebResponse 响应字符串被截断

    应用程序正在与 REST 服务通信 Fiddler 显示作为 Apps 响应传入的完整良好 XML 响应 该应用程序位于法属波利尼西亚 在新西兰也有一个相同的副本 因此主要嫌疑人似乎在编码 但我们已经检查过 但空手而归 查看流读取器的输出字
  • C++ OpenSSL 导出私钥

    到目前为止 我成功地使用了 SSL 但遇到了令人困惑的障碍 我生成了 RSA 密钥对 之前使用 PEM write bio RSAPrivateKey 来导出它们 然而 手册页声称该格式已经过时 实际上它看起来与通常的 PEM 格式不同 相
  • 转发声明和包含

    在使用库时 无论是我自己的还是外部的 都有很多带有前向声明的类 根据情况 相同的类也包含在内 当我使用某个类时 我需要知道该类使用的某些对象是前向声明的还是 include d 原因是我想知道是否应该包含两个标题还是只包含一个标题 现在我知
  • 如何查看网络连接状态是否发生变化?

    我正在编写一个应用程序 用于检查计算机是否连接到某个特定网络 并为我们的用户带来一些魔力 该应用程序将在后台运行并执行检查是否用户请求 托盘中的菜单 我还希望应用程序能够自动检查用户是否从有线更改为无线 或者断开连接并连接到新网络 并执行魔
  • 对现有视频添加水印

    我正在寻找一种用 C 在视频上加水印的方法 就像在上面写文字一样 图片或文字标签 我该怎么做 谢谢 您可以使用 Nreco 视频转换器 代码看起来像 NReco VideoConverter FFMpegConverter wrap new
  • 向现有 TCP 和 UDP 代码添加 SSL 支持?

    这是我的问题 现在我有一个 Linux 服务器应用程序 使用 C gcc 编写 它与 Windows C 客户端应用程序 Visual Studio 9 Qt 4 5 进行通信 是什么very在不完全破坏现有协议的情况下向双方添加 SSL
  • 如何在Xamarin中删除ViewTreeObserver?

    假设我需要获取并设置视图的高度 在 Android 中 众所周知 只有在绘制视图之后才能获取视图高度 如果您使用 Java 有很多答案 最著名的方法之一如下 取自这个答案 https stackoverflow com a 24035591
  • 测试用例执行完成后,无论是否通过,如何将测试用例结果保存在变量中?

    我正在使用 NUNIT 在 Visual Studio 中使用 Selenium WebDriver 测试用例的代码是 我想在执行测试用例后立即在变量中记录测试用例通过或失败的情况 我怎样才能实现这一点 NUnit 假设您使用 NUnit
  • 如何将服务器服务连接到 Dynamics Online

    我正在修改内部管理应用程序以连接到我们的在线托管 Dynamics 2016 实例 根据一些在线教程 我一直在使用OrganizationServiceProxy out of Microsoft Xrm Sdk Client来自 SDK

随机推荐

  • sql server 经典练习题分享二

    26 查询存在有85分以上成绩的课程Cno SELECT DISTINCT cno FROM dbo scores WHERE degree gt 85 27 查询出 计算机系 教师所教课程的成绩表 SELECT tname prof cn
  • 23. 客户默认选项(Default Customer Options)

    Editing Email Templates Email Sender Contact Us
  • iphone尺寸_2007至2020:最全的iPhone手机25部历代发展及价格变化历史

    所以iPhone SE 2020 是真的廉价倒地了 智能手机时代的开始 第一代iPhone 2G 2007 4G 3800 8G 4560 2007年 史蒂夫 乔布斯 Steve Jobs 穿着运动鞋 牛仔裤 T恤站在舞台上 宣布了第一部i
  • Maven、pom.xml

    maven库中心 Maven Central Repository Search 搜索可以用的包与版本 目录 Maven 使用方法 1 下载 配置 2 项目中使用 3 生命周期 4 构建插件 MAVEN工程 的目录结构 父子项目 创建父项目
  • dpr-2000 四usb口无线多功能打印服务器,D-Link DPR-2000 超高兼容的打印服务器

    PConline资讯 DPR 2000无线802 11 G多功能打印服务器是一个通用多端口的打印服务器 是办公 学校和商业使用的理想选择 它提供4个USB连接接口可以连接4台USB打印机 本设备给用户提供添加多个打印机 多功能打印机或扫描仪
  • vue项目使用luckyexcel插件预览excel表格

    温馨提示 需要用到luckysheet文件和luckyexcel插件 根据下面步骤一步一步操作会避免踩坑 比如我当时遇到了window luckysheet is not defined控制台报红的问题 第一步 引入luckysheet的相
  • JAVA单元测试框架-14-实现TestNG失败案例重跑

    前面是通过java代码指定重跑 本节是讲解通过实现IAnnotationTransformer接口实现失败案例重跑 创建MyRetry 实现IRetryAnalyzer 接口 package Listener import org test
  • MMsegmentation文档学习

    1 了解配置 config文件结构 config base 下有4种基本组件类型 dataset model schedule default runtime 同一文件夹下的所有配置 建议只具有一个原始配置 所有其他配置从原始配置继承 这样
  • JDK8升级JDK11最全实践干货来了

    1 前言 截至目前 2023年 Java8发布至今已有9年 2018年9月25日 Oracle发布了Java11 这是Java8之后的首个LTS版本 那么从JDK8到JDK11 到底带来了哪些特性呢 值得我们升级吗 而且升级过程会遇到哪些问
  • Ts接口的使用

    TypeScript 的核心原则之一是对值所具有的结构进行类型检查 我们使用接口 Interfaces 来定义对象的类型 接口是对象的状态 属性 和行为 方法 的抽象 描述 接口初探 需求 创建人的对象 需要对人的属性进行一定的约束 id是
  • 工作10年我面试过上百个程序员,真想对他们说…

    V xin ruyuanhadeng获得600 页原创精品文章汇总PDF 一 写在前面 最近收到不少读者反馈 说自己在应聘一些中大型互联网公司的Java工程师岗位时遇到了不少困惑 这些同学说自己也做了精心准备 网上搜集了不少Java面试题
  • Edit Distance

    Given two words word1 and word2 find the minimum number of steps required to convert word1 to word2 each operation is co
  • 【转载】探索推荐引擎内部的秘密

    原网址 https www ibm com developerworks cn web 1103 zhaoct recommstudy1 index html icomments 这是2011年ibm发布的文章 较为通俗易懂 适合想入门推荐
  • 配置msf连接postgresql数据库

    BackTrack 5 R3版本的Metasploit在每次的升级后总会出现奇奇怪怪的错误 主要是Ruby的库出错 网上找了一些解决的办法 但每次更新后又会出错 蛋碎 解决方法 BackTrack 5中默认自动开启端口7337 1 查看Po
  • Zabbix监控MariaDB服务

    文章目录 1 概述监控MariaDB服务主机 2 安装MariaDB服务和配置MariaDB 3 配置Zabbix的userparameter mysql conf 文件模板 4 在Web配置模板 5 在server进行压力测试mysql服
  • svg实现文本的垂直居中对齐样式

    项目中用到表格内画折线趋势图 本人使用的svg绘制简单折线 没有数据的单元格显示文字 为了不影响表格的宽度自适应 就想到在svg上写文字 于是就有了在svg上对文字样式进行垂直居中的需求 上代码
  • Linux教程:在虚拟机中如何配置Linux系统网络环境 ?

    对于很多初学Linux 的同学 大多选择使用虚拟机来展开学习 可以方便的做实验 修改 测试 不必害怕出问题 可以随便折腾 大不了换一个虚拟机 原来的系统不受任何影响 但由于不是实体pc机 使用难免受限 如果配置不好 后期开发必受其累 比如
  • C++Primer(4-8章)

    第四章 表达式 求值顺序 C 中没有明确规定大多数运算符的求值顺序 因此我们要避免 改变了某个运算对象的值 又在表达式其他地方使用这个运算对象 这种情况出现 赋值运算满足右结合律 在输出表达式中使用条件运算符 条件运算符的优先级非常低 因此
  • java修改AD域用户密码使用SSL连接方式

    正常情况下 JAVA修改AD域用户属性 只能修改一些普通属性 如果要修改AD域用户密码和userAccountControl属性就得使用SSL连接的方式修改 SSL连接的方式需要操作以下步骤 1 安装AD域证书服务 2 证书颁发机构中设置以
  • 【C语言】结构体中的函数指针

    目录 一 函数指针是什么 二 结构体中的函数指针 一 函数指针是什么 函数指针是指向函数的指针变量 通常我们说的指针变量是指向一个整型 字符型或数组等变量 而函数指针是指向函数 函数指针可以像一般函数一样 用于调用函数 传递参数 正确形式