函数指针初始化和调用的几种方法

本文探讨了函数指针的两种初始化方式及其原因,并介绍了三种函数调用方式的区别。此外,还列举了函数指针的主要用途,如回调函数和转移表。

文章转自:http://blog.youkuaiyun.com/zongyinhu/article/details/48790555

看如下代码,然后思考如下几个问题:

  1. <span style="font-family:KaiTi_GB2312;font-size:18px;">#include<iostream>  
  2. #include<cstdlib>  
  3. using namespace std;  
  4.   
  5. int func()  
  6. {  
  7.     cout << "my name is zyh_helen" << endl;  
  8.     return 0;  
  9. }  
  10.   
  11. int main()  
  12. {  
  13.     int(*p)() = func;   //函数指针初始化方式1  
  14.     int(*p1)() = &func; //函数指针初始化方式2  
  15.   
  16.     func();//函数调用方式1  
  17.     (*p)();//函数调用方式2  
  18.     p();   //函数调用方式3  
  19.   
  20.     system("pause");  
  21.     return 0;  
  22. }</span>  

问题1:初始化函数指针时,为何既可以在函数名之前加&操作符,又可以不加?

问题2:函数调用方式有几种,他们之间的区别是什么?

问题3:函数指针的用途有哪些?



1:函数指针初始化方式有两种:

方式2中的&操作符是可选因为函数名被使用时总是由编译器把它转化为函数指针,&操作符只是显示的说明了编译器将隐式执行的任务

2:函数调用方式有三种:

函数调用方式1:使用函数名调用函数,执行过程可能和你想象的不一样,函数名首先被转化为一个函数指针,该指针指定函数在内存中的位置,然后,函数调用操作符()调用该函数,执行开始于这个地址的代码。
函数调用方式2:首先对p执行间接访问操作,它把函数指针转化为一个函数名,这个转换并不是真正需要的,因为编译器在执行函数调用操作符之前又会把它转换回去
函数调用方式3:省去了编译器的隐式转化
因此,通过函数指针调用函数时,最好选择方式3

3:函数指针的用途:

1:回调函数:用户把一个函数指针作为参数传递给其他函数,后者将“回调”用户的函数
2:转移表  :本质:一个函数指针数组
<think>首先,用户的问题是:“请问如何在C语言中正确初始化函数指针”。根据系统指令,我需要使用中文回答,确保回答结构清晰,帮助用户逐步解决问题。 关键点: - 用户意图是了解函数指针初始化。 - 系统指令要求:行内数学表达式用$...$,独立公式用$$...$$,但这里可能不需要数学公式,因为主题是C语言编程。 - 生成相关问题。 - 在回答中引用的段落末尾添加引用标识,如[^1]。 参考提供的引用: - 引用[1]:关于结构体指针初始化,强调需要分配内存。 - 引用[2]:指针操作,包括自增。 - 引用[3]:函数指针的示例代码。 - 引用[4]:函数指针数组的应用场景。 用户意图聚焦在函数指针初始化上,所以我会基于引用[3]来构建回答。 结构化回答: 1. **介绍函数指针**:简要解释什么是函数指针。 2. **初始化方法**:逐步说明如何初始化函数指针。 - 声明函数指针。 - 赋值函数地址。 3. **示例代码**:提供C语言代码示例。 4. **注意事项**:包括常见错误最佳实践。 5. **生成相关问题**:在最后添加相关问题。 回答必须真实可靠,基于C语言标准。 步骤: - 声明函数指针:使用语法 `return_type (*pointer_name)(parameters);` - 初始化:通过赋值函数名,因为函数名本身就是地址。 - 在代码中展示。 最终回答: - 以中文清晰解释。 - 结尾添加相关问题。</think>### 如何在C语言中正确初始化函数指针 在C语言中,函数指针用于存储函数的地址,允许通过指针调用函数。正确初始化函数指针是避免程序崩溃(如段错误)的关键。以下是逐步说明示例: #### 1. **函数指针的声明** - 函数指针的声明语法为:`返回类型 (*指针名)(参数列表);`。 - 示例:声明一个指向返回 `int` 类型、接受一个 `int` 参数的函数指针: ```c int (*func_ptr)(int); // 声明函数指针 func_ptr ``` - 这里,`func_ptr` 是一个指针变量,可以存储符合该签名的函数地址。 #### 2. **初始化函数指针** - **赋值初始化**:直接将函数名赋值给指针函数名本身代表函数的地址。 - 步骤: 1. 定义一个匹配的函数(例如,`int my_function(int x)`)。 2. 将函数名赋值给指针:`func_ptr = my_function;`。 - 示例代码: ```c #include <stdio.h> // 定义匹配的函数 int add_one(int x) { return x + 1; } int main() { int (*func_ptr)(int); // 声明函数指针 func_ptr = add_one; // 初始化:赋值函数地址 // 测试调用 int result = func_ptr(5); // 相当于调用 add_one(5) printf("结果: %d\n", result); // 输出: 结果: 6 return 0; } ``` - **关键点**:函数名 `add_one` 自动解析为地址,不需要使用 `&` 运算符(如 `func_ptr = &add_one;` 也可,但通常省略)。 - **声明时初始化**:在声明指针的同时赋值。 - 示例: ```c int (*func_ptr)(int) = add_one; // 声明并初始化 ``` #### 3. **注意事项** - **匹配函数签名**:函数指针必须与目标函数的返回类型参数列表完全匹配。否则,会导致未定义行为。 - 错误示例:如果 `add_one` 定义为 `int add_one(int x)`,但指针声明为 `int (*func_ptr)(void);`(无参数),则初始化无效。 - **避免野指针**:始终在赋值前确保指针指向有效函数。未初始化函数指针可能指向随机内存地址,调用时会导致崩溃。 - 正确做法:在声明后立即赋值,或初始化为 `NULL` 并在使用前检查: ```c int (*func_ptr)(int) = NULL; // 初始化为 NULL if (func_ptr != NULL) { func_ptr(5); // 安全调用 } ``` - **动态内存场景**:如果函数指针作为结构体成员或数组元素,需确保其指向的函数在作用域内有效(静态函数或全局函数)。引用[1]提到结构体指针初始化时需分配内存,但函数指针本身不分配内存,只需赋值地址[^1]。 - **指针运算**:函数指针不支持算术运算(如 `func_ptr++`),因为函数地址在内存中不连续。引用[2]解释了指针自增的细节,但不适用于函数指针[^2]。 #### 4. **完整示例代码** 以下代码演示了函数指针的声明、初始化调用: ```c #include <stdio.h> // 定义两个匹配的函数 int multiply_by_two(int x) { return x * 2; } int add_five(int x) { return x + 5; } int main() { // 声明并初始化函数指针 int (*func_ptr1)(int) = multiply_by_two; int (*func_ptr2)(int) = add_five; // 通过指针调用函数 printf("multiply_by_two(3) = %d\n", func_ptr1(3)); // 输出: 6 printf("add_five(3) = %d\n", func_ptr2(3)); // 输出: 8 return 0; } ``` #### 5. **应用场景** 函数指针常用于回调机制、状态机或策略模式,如引用[4]所述[^4]。例如,在事件处理中,根据输入动态选择处理函数: ```c void process_input(int input, int (*handler)(int)) { int result = handler(input); // 通过函数指针调用 printf("处理结果: %d\n", result); } ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值