指向函数的指针

假定我们被要求提供一个如下形式的排序函数 :
sort( start, end, compare );
start 和 end是指向字符串数组中元素的指针,函数 sort()对于 start 和end之间的数组元素进行排序,compare 定义了比较数组中两个字符串的比较操作(提供一个比较的策略【比较函数 】)。

为简化 sort()的用法而又不限制它的灵活性,我们可能希望指定一个缺省的比较函数。

如何来实现呢?compare可能指向不同的排序方法,解决这些需求的一种策略是将第三个参数compare 设为函数指针,并由它指定要使用的比较函数

一、指向函数的指针的类型

怎样声明指向函数的指针呢 用函数指针作为实参的参数会是什么样呢,下面是函数lexicoCompare()的定义,它按字典序比较两个字符串 
#include <string>
 
int lexicoCompare( const string &s1, const string &s2 ) {
return s1.compare(s2);
}

函数名不是其类型的一部分,函数的类型只由它的返回值和参数表决定,指向lexicoCompare()的指针必须指向与lexicoCompare()相同类型的函数:带有相同的返回类型和相同的参数表,让我们试一下: 
int *pf( const string &, const string & ); // 喔! 差一点

这几乎是正确的,问题是编译器把该语句解释成名为pf的函数的声明,它有两个参数并且返回一个int*型的指针,参数表是正确的,但是返回值不是我们所希望的解引用操作符(*)应与返回类型关联,所以在这种情况下是与类型名 int 关联,而不是 pf ,要想让解 引用操作符与pf关联,括号是必需的: 

int (*pf)( const string &, const string & ); // ok: 正确
这个语句声明了pf是一个指向函数的指针,该函数有两个参数和 int 型的返回值,即指向函数的指针,它与 lexicoCompare()的类型相同,下列函数与lexicoCompare()类型相同,都可以用 pf来指向: 
int sizeCompare( const string &, const string & );

但是 calc()和gcd()与前面两个函数的类型不同 不能用 Pf来指 
int calc( int , int );
int gcd( int , int );
可以如下定义 pfi 它能够指向这两个函数 
int (*pfi)( int, int );


省略号是函数类型的一部分,如果两个函数具有相同的参数表,但是一个函数在参数表末尾有省略号,则它们被视为不同的函数类型,指向这两个函数的指针类型也不同 
int printf( const char*, ... );
int strlen( const char* );
 
int (*pfce)( const char*, ... ); // 可以指向 printf()
int (*pfc)( const char* ); // 可以指向 strlen()
函数返回类型和参数表的不同组合 代表了各不相同的函数类型 

二、初始化和赋值

我们知道,不带下标操作符的数组名会被解释成指向首元素的指针,当一个函数名没被调用操作符修饰时,会被解释成指向该类型函数的指针,例如,表达式:
lexicoCompare;
被解释成类型
int (*)( const string &, const string & );
的指针

 
将取地址操作符作用在函数名上也能产生指向该函数类型的指针因此 lexicoComp和&lexioCompare类型相同,指向函数的指针可如下被初始化  :
int (*pfi)( const string &, const string & ) = lexicoCompare;
int (*pfi2)( const string &, const string & ) = &lexicoCompare;

 

指向函数的指针可以如下被赋值 :
pfi = lexicoCompare;
pfi2 = pfi;


只有当赋值操作符左边指针的参数表和返回类型与右边函数或指针的参数表和返回类完全匹配时,初始化和赋值才是正确的,如果不匹配,则将产生编译错误消息,在指向函类型的指针之间不存在隐式类型转换,例如 :
int calc( int, int );
int (*pfi2s)( const string &, const string & ) = 0;
int (*pfi2i)( int, int ) = 0;
 
int main() {
pfi2i = calc; // ok
pfi2s = calc; // 错误: 类型不匹配
pfi2s = pfi2i; // 错误: 类型不匹配
return 0;
}
函数指针可以用 0 来初始化或赋值 以表示该指针不指向任何函数 

三、调用

向函数的指针可以被用来调用它所指向的函数,调用函数时,不需要解引用操作符,无论是用函数名直接调用函数,还是用指针间接调用函数,两者的写法是一样的,例如 :
#include <iostream>
 
int min( int*, int );
int (*pf)( int*, int ) = min;
 
const int iaSize = 5;
int ia[ iaSize ] = { 7, 4, 9, 2, 5 };
 
int main() {
cout << "Direct call: min: "

  << min( ia, iaSize ) << endl;
 
cout << "Indirect call: min: "
  << pf( ia, iaSize ) << endl;
return 0;
}


int min( int* ia, int sz ) {
int minVal = ia[ 0 ];


for ( int ix = 1; ix < sz; ++ix )
  if ( minVal > ia[ ix ] )
   minVal = ia[ ix ];
return minVal;
}


调用
pf( ia, iaSize );
也可以用显式的指针符号写出 
(*pf)( ia, iaSize );
这两种形式产生相同的结果,但是第二种形式让读者更清楚该调用是通过函数指针执行的 。

 
当然,如果函数指针的值为 0,则两个调用都将导致运行时刻错误,只有已经被初始化或赋值的指针引用到一个函数,才可以被安全地用来调用一个函数。

【博士论文复现】【阻抗建模、验证扫频法】光伏并网逆变器扫频与稳定性分析(包含锁相环电流环)(Simulink仿真实现)内容概要:本文档是一份关于“光伏并网逆变器扫频与稳定性分析”的Simulink仿真实现资源,重点复现博士论文中的阻抗建模与扫频法验证过程,涵盖锁相环和电流环等关键控制环节。通过构建详细的逆变器模型,采用小信号扰动方法进行频域扫描,获取系统输出阻抗特性,并结合奈奎斯特稳定判据分析并网系统的稳定性,帮助深入理解光伏发电系统在弱电网条件下的动态行为与失稳机理。; 适合人群:具备电力电子、自动控制理论基础,熟悉Simulink仿真环境,从事新能源发电、微电网或电力系统稳定性研究的研究生、科研人员及工程技术人员。; 使用场景及目标:①掌握光伏并网逆变器的阻抗建模方法;②学习基于扫频法的系统稳定性分析流程;③复现高水平学术论文中的关键技术环节,支撑科研项目或学位论文工作;④为实际工程中并网逆变器的稳定性问题提供仿真分析手段。; 阅读建议:建议读者结合相关理论教材与原始论文,逐步运行并调试提供的Simulink模型,重点关注锁相环与电流控制器参数对系统阻抗特性的影响,通过改变电网强度等条件观察系统稳定性变化,深化对阻抗分析法的理解与应用能力。
### 指向函数指针的概念 指向函数指针是一种指针类型,它指向一个函数。通过这种指针,可以像调用普通函数一样调用它所指向函数。在C语言中,函数指针提供了一种将函数作为参数传递、存储函数地址以及在运行时动态调用函数的机制。函数指针数组是一个数组,其每个元素都是一个函数指针;而指向函数指针数组的指针则是指向这个函数指针数组的指针 [^1]。 ### 使用方法 - **动态分配函数指针数组**:当函数指针数组的大小需要在运行时动态确定时,可使用指向函数指针数组的指针来动态分配内存,使用`malloc`或`calloc`函数分配适当大小的函数指针数组,并将其地址赋给指向函数指针数组的指针 [^1]。 - **获取函数指针数组的大小**:通过指向函数指针数组的指针,可获取函数指针数组的大小,通过递减指针并检查数组元素的值,直到找到一个`NULL`值 [^1]。 - **遍历函数指针数组**:指向函数指针数组的指针可用来遍历函数指针数组中的元素,通过递增或递减指针,从而调用数组中的每个函数 [^1]。 - **模块化编程**:在大型项目中,可将不同的功能模块分配给不同的团队开发,使用指向函数指针数组的指针能方便地将不同的功能模块集成到主程序中,通过调用不同的函数指针数组元素,实现对各个功能模块的调用 [^1]。 ### 示例 以下是一些指向函数指针相关的代码示例: ```c #include <stdio.h> #include <stdlib.h> // 示例函数 int Add(int x, int y) { return x + y; } int main() { // 函数指针 int (*pAdd)(int, int) = Add; // 函数指针的数组 int (*pArr[5])(int, int); pArr[0] = Add; // 指向函数指针数组的指针 int (*(*ppArr)[5])(int, int) = &pArr; // 调用函数 int result = (*(*ppArr)[0])(2, 3); printf("Result of Add: %d\n", result); return 0; } ``` 在上述示例中,定义了一个`Add`函数,然后创建了一个函数指针`pAdd`指向函数,接着创建了一个函数指针数组`pArr`,并将`pAdd`赋值给数组的第一个元素。最后,创建了一个指向函数指针数组的指针`ppArr`,并通过该指针调用了数组中的函数 [^1]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值