指向函数的指针

假定我们被要求提供一个如下形式的排序函数 :
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,则两个调用都将导致运行时刻错误,只有已经被初始化或赋值的指针引用到一个函数,才可以被安全地用来调用一个函数。

【电能质量扰动】基于ML和DWT的电能质量扰动分类方法研究(Matlab实现)内容概要:本文研究了一种基于机器学习(ML)和离散小波变换(DWT)的电能质量扰动分类方法,并提供了Matlab实现方案。首先利用DWT对电能质量信号进行多尺度分解,提取信号的时频域特征,有效捕捉电压暂降、暂升、中断、谐波、闪变等常见扰动的关键信息;随后结合机器学习分类器(如SVM、BP神经网络等)对提取的特征进行训练与分类,实现对不同类型扰动的自动识别与准确区分。该方法充分发挥DWT在信号去噪与特征提取方面的优势,结合ML强大的模式识别能力,提升了分类精度与鲁棒性,具有较强的实用价值。; 适合人群:电气工程、自动化、电力系统及其自动化等相关专业的研究生、科研人员及从事电能质量监测与分析的工程技术人员;具备一定的信号处理基础和Matlab编程能力者更佳。; 使用场景及目标:①应用于智能电网中的电能质量在线监测系统,实现扰动类型的自动识别;②作为高校或科研机构在信号处理、模式识别、电力系统分析等课程的教学案例或科研实验平台;③目标是提高电能质量扰动分类的准确性与效率,为后续的电能治理与设备保护提供决策依据。; 阅读建议:建议读者结合Matlab代码深入理解DWT的实现过程与特征提取步骤,重点关注小波基选择、分解层数设定及特征向量构造对分类性能的影响,并尝试对比不同机器学习模型的分类效果,以全面掌握该方法的核心技术要点。
### 指向函数指针的概念 指向函数指针是一种指针类型,它指向一个函数。通过这种指针,可以像调用普通函数一样调用它所指向函数。在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、付费专栏及课程。

余额充值