`
lgh1992314
  • 浏览: 315624 次
文章分类
社区版块
存档分类
最新评论

指向函数的指针

 
阅读更多
#include<iostream>
using namespace std;
int max(int x,int y)
{
	return x>y?x:y;
}
int main()
{
	int (*p)(int,int);
	p = max;
	cout<<(*p)(4,5)<<endl;
	cout<<max(4,5)<<endl;
}

int (*p)( int,int ); 用来定义 p 是一个指向函数的指针变量,该函数有两个整形参数,函数值为整形。注意 *p 两侧的括号不可省略,表示 p 先与 * 结合,是指针变量,然后再与后面的 ( ) 结合,表示此指针变量指向函数,这个函数值 (即函数的返回值) 是整形的。如果写成 int *p ( int,int ) ,由于( )的优先级高于 *,它就成了声明一个函数P( 这个函数的返回值是指向整形变量的指针)。

赋值语句 p = max ; 作用是将函数 max 的入口地址赋给指针变量p。和数组名代表数组首元素地址类似,函数名代表该函数的入口地址。这时 p 就是指向函数 max 的指针变量,此时 p 和 max都指向函数开头,调用 *p 就是调用 max 函数。但是p作为指向函数的指针变量,它只能指向函数入口处而不可能指向函数中间的某一处指令处,因此不能用 *(p + 1)来表示指向下一条指令。


注意:


  (1) 指向函数的指针变量的一般定义形式为:


  数据类型 (*指针变量名)(函数参数列表)


  这里数据类型就是函数返回值的类型


  (2) int (* p) ( int,int ); 它只是定义一个指向函数的指针变量 p, 它不是固定指向哪一个函数的,而只是表示定义这样一个类型的变量,它是专门用来存放函数的入口地址的。在程序中把哪一函数(该函数的值应该是整形的,且有两个整形参数)的地址赋给它,他就指向哪一个函数。在一个函数中,一个函数指针变量可以先后指向同类型的不同函数。


  (3) p = max; 在给函数指针变量赋值时,只需给出函数名而不必给出函数参数,因为是将函数的入口地址赋给 p ,而不涉及 实参和形参的结合问题,不能写成 p = max(a,b);


  (4) c = (*p)(a,b) 在函数调用时,只需将( *p ) 代替函数名即可,后面实参依旧。


  (5) 对于指向函数的指针变量,像 p++ ,p+n.....是无意义的。


  (二) 用指向函数的指针作为函数参数


  函数指针变量通常的用途之一就是把指针作为参数传递到其他函数。


  函数的参数可以是变量、指向变量的指针变量、数组名、指向数组的指针变量,也可以是指向函数的指针也可以作为参数,以实现函数地址的传递,这样就能够在被调用的函数中使用实参函数。


  void sub ( int ( *x1) (int), int (*x2) (int,int) )


    {


      int a,b,i,j;


      a = (*x1)(i);      /* 调用 f1 函数 */


      b = (*x2)(i)(j);    /* 调用 f2 函数 */


    }


  如果实参为两个 函数名 f1 和 f2. 在函数首部定义x1、x2为函数指针变量,x1指向的函数有一个整形形参,x2指向的函数有两个形参。i 和 j 是函数f1 和 f2所要的参数。函数sub的形参 x1、x2(指针变量)在函数 sub 未被调用时并不占用内存单元,也不指向任何函数。在sub被调用时,把实参函数 f1 和 f2的入口地址传给形式指针变量 x1 和 x2.


  既然在 sub 函数中要调用 f1 和 f2 函数,为什么不直接调用f1 和 f2而要用函数指针变量呢? 确实,如果只是用到f1 和 f2 函数,完全可以在sub函数中直接调用f1 和 f2,而不必设指针变量 x1 和 x2。 但是,如果在每次调用sub时,调用的函数不是固定的,下次是f3 和 f4,再是f5 和 f6...这时用指针变量就比较方便了。



http://blog.csdn.net/wuliming_sc/article/details/3855682

指向函数的指针

假定我们被要求提供一个如下形式的排序函数:

sort( start, end, compare );

startend是指向字符串数组中元素的指针。函数sort()对于startend之间的数组元素进行排序。compare定义了比较数组中两个字符串的比较操作。

该怎样实现compare呢?我们或许想按字典顺序排序数组内的字符串或许想按长度排序它们,以便将最短的字符串放在前面,而长的放在后面。解决这种需求的一种策略是将第三个参数compare设为函数指针,并由它指定要使用的比较函数。

为简化sort()的用法而又不限制它的灵活性,我们可能希望指定一个缺省的比较函数,以用于大多数的情况。让我们假设最常见的以字典序排列字符串的情况,缺省实参将指定一个比较操作,它用到了字符串的compare()函数。我们将考虑怎样用函数指针来实现我们的sort()函数。

指向函数的指针的类型

怎样声明指向函数的指针呢?用函数指针作为实参的参数会是什么样呢?下面是函数lexicoCompare()的定义,它按字典序比较两个字符串:

#include <string>

int lexicoCompare( const string &s1, const string &s2 ) {

return s1.compare(s2);

}

如果字符串s1s2中的所有字符都相等,则lexicoCompare()返回0否则,如果第一个参数表示的字符串小于第二个参数表示的字符串,则返回一个负数;如果大于,则返回一个正数。

函数名不是其类型的一部分,函数的类型只由它的返回值和参数表决定。指向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 );

初始化和赋值

我们知道,不带下标操作符的数组名会被解释成指向首元素的指针。当一个函数名没有被调用操作符修饰时,会被解释成指向该类型函数的指针。例如,表达式

lexicoCompare

被解释成类型:

int (*)( const string &, const string & );

的指针。

将取地址操作符作用在函数名上也能产生指向该函数类型的指针。因此,lexicoCompare&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则两个调用都将导致运行时刻错误。只有已经被初始化或赋值的指针(引用到一个函数)才可以被安全地用来调用一个函数。

函数指针的数组

我们可以声明一个函数指针的数组。例如:

int (*testCases[10])();

testCases声明为一个拥有10个元素的数组。每个元素都是一个指向函数的函数指针,该函数没有参数,返回类型为int

像数组testCases这样的声明非常难读,因为很难分析出函数类型与声明的哪部分相关。在这种情况下,使用typedef名字可以使声明更为易读。例如:

// typedefs使声明更易读

typedef int (*PFV)(); //定义函数类型指针的typedef

PFV testCases[10];

testCases的这个声明与前面的等价。

testCases的一个元素引用的函数调用如下:

const int size = 10;

PFV testCases[size];

int testResults[size];

void runtests() {

for ( int i = 0; i < size; ++i )

//调用一个数组元素

testResults[ i ] = testCases[ i ]();

}

函数指针的数组可以用一个初始化列表来初始化,该表中每个初始值都代表了一个与数组元素类型相同的函数。例如:

int lexicoCompare( const string &, const string & );

int sizeCompare( const string &, const string & );

typedef int ( *PFI2S )( const string &, const string & );

PFI2S compareFuncs[2] = {

lexicoCompare,

sizeCompare

};

我们也可以声明指向compareFuncs的指针。这种指针的类型是“指向函数指针数组的指针”。声明如下:

PFI2S (*pfCompare)[2] = &compareFuncs;

声明可以分解为:

(*pfCompare)

解引用操作符*pfCompare声明为指针,后面的[2]表示pfCompare是指向两个元素数组的指针:

(*pfCompare)[2]

typedef PFI2S表示数组元素的类型,它是指向函数的指针,该函数返回int有两个const string&型的参数。数组元素的类型与表达式&lexicoCompare的类型相同,也与compareFuncs的第一个元素的类型相同。此外,它还可以通过下列语句之一获得:

compareFuncs[ 0 ];

(*pfCompare)[ 0 ];

要通过pfCompare调用lexicoCompare程序员可用下列语句之一:

//两个等价的调用

pfCompare[ 0 ]( string1, string2 ); //编写

((*pfCompare)[ 0 ])( string1, string2 ); //显式

参数和返回类型

现在我们回头看一下本节开始提出的问题,在那里给出的任务要求我们写一个排序函数,怎样用函数指针写这个函数呢?因为函数参数可以是函数指针,所以我们把表示所用比较操作的函数指针作为参数传递给排序函数:

int sort( string*, string*,

int (*)( const string &, const string & ) );

我们再次用typedef名字使sort()的声明更易读:

// typedef使sort()的声明更易读

typedef int ( *PFI2S )( const string &, const string & );

int sort( string*, string*, PFI2S );

因为在多数情况下使用的函数是lexicoCompare()所以我们让它成为缺省的函数指针参数:

//提供缺省参数作为第三个参数

int lexicoCompare( const string &, const string & );

int sort( string*, string*, PFI2S = lexicoCompare );

sort()函数的定义可能像这样:

void sort( string *s1, string *s2, PFI2S compare = lexicoCompare )

{

//递归的停止条件

if ( s1 < s2 ) {

string elem = *s1;

string *low = s1;

string *high = s2 + 1;

for (;;) {

while ( compare( *++low, elem ) < 0 && low < s2) ;

while ( compare( elem, *--high ) < 0 && high > s1) ;

if ( low < high )

low->swap(*high);

else break;

} // end, for(;;)

s1->swap(*high);

sort( s1, high - 1, compare );

sort( high + 1, s2, compare );

} // end, if ( s1 < s2 )

}

sort()C.A.R.Hoare的快速排序算法的一个实现。让我们详细查看该函数的定义。该函数对s1s2之间的数组元素进行排序。sort()是一个递归函数,它将自己逐步地应用在较小的子数组上。停止条件是当s1指向与s2相同的元素时或指向s2所指元素之后的元素(第5行)。

elem6行)被称作分割元素所有按字典序小于elem的元素部会被移到elem的左边,而所有大于的都被移到右边。现在,数组被分成若干个子数组,sort()被递归地应用在它们之上。

for(;;)循环的目的是完成分割。在循环的每次迭代中,low首先被向前移动到第一个大于等于elem的数组元素的索引上。类似地,high一直被递减,直到移动到小于等于elem的数组最右元素的索引上。如果low不再小于high则表示元素已经分隔完毕,循环结束。否则,这两个元素被交换,下一次迭代开始。虽然数组已经被分隔,但elem仍然是数组的第一个元素。在sort()被应用到两个子数组之前,第19行的swap()elem放到它在数组中最终正确的位置上。

数组元素的比较通过调用compare指向的函数来完成。swap()字符串操作被调用,以便交换数组元素所指的字符串

下面main()的实现用到了我们的排序函数:

#include <iostream>

#include <string>

//这些通常应该在头文件中

intlexicoCompare( const string &, const string & );

intsizeCompare( const string &, const string & );

typedef int (*PFI)( const string &, const string & );

voidsort( string *, string *, PFI=lexicoCompare );

string as[10] = { "a", "light", "drizzle", "was", "falling","when", "they", "left", "the", "museum" };

int main() {

//调用sort(),使用缺省实参作比较操作

sort( as, as + sizeof(as)/sizeof(as[0]) - 1 );

//显示排序之后的数组的结果

for ( int i = 0; i < sizeof(as)/sizeof(as[0]); ++i )

cout << as[ i ].c_str() << "/n/t";

}

编译并执行程序,生成下列输出:

"a"

"drizzle"

"falling"

"left"

"light"

"museum"

"the"

"they"

"was"

"when"

函数参数的类型不能是函数类型,函数类型的参数将被自动转换成该函数类型的指针。例如:

// typedef表示一个函数类型

typedef int functype( const string &, const string & );

void sort( string *, string *, functype );

编译器把sort()当作已经声明为:

void sort( string *, string *, int (*)( const string &, const string & ) );

上面这两个sort()的声明是等价的。

注意,除了用作参数类型之外,函数指针也可以被用作函数返回值的类型。例如:

int (*ff( int ))( int*, int );

该声明将ff()声明为一个函数,它有一个int型的参数,返回一个指向函数的指针,类型为:

int (*) ( int*, int );

同样,使用typedef名字可以使声明更容易读懂。例如,下面的typedef PF使得我们能更容易地分解出ff()的返回类型是函数指针:

// typedef使声明更易读

typedef int (*PF)( int*, int );

PF ff( int );

函数不能声明返回一个函数类型。如果是,则产生编译错误。例如,函数ff()不能如下声明:

// typedef表示一个函数类型

typedef int func( int*, int );

func ff( int ); //错误: ff()的返同类型为函数类型


分享到:
评论

相关推荐

    指向函数的指针运用

    压缩包中的`指向函数的指针.cpp`文件应该包含了上述所有代码的实现,而`指向函数的指针.exe`则是编译后的可执行程序,运行这个程序将演示如何通过函数指针调用和比较两个积分函数。 总结来说,这个示例展示了C++中...

    函数指针就是指向函数的指针;类成员方法指针,类具有类域操作符

    在C++编程中,函数指针是一个非常重要的概念,它允许我们存储函数的地址并像普通指针一样对其进行操作。函数指针可以被用来作为参数传递给其他函数,或者存储在一个变量中,以便稍后调用。这为程序设计提供了很大的...

    C/C++ 函数指针的意义,函数指针的用法

    ### C/C++ 函数指针的意义与应用 在C/C++编程中,函数指针是一种高级特性,它允许程序员处理函数的方式如同处理变量一般灵活。理解函数指针的意义及其用法,对于提升代码的可扩展性和灵活性至关重要。 #### 1. ...

    c++中指向函数的指针

    在C++中,指向函数的指针是一种强大的工具,它允许我们存储函数的地址并以指针的形式调用它们。这种技术在某些情况下非常有用,比如动态选择执行哪个函数、作为参数传递给其他函数或者作为函数的返回值。下面我们将...

    函数指针详解 word文档讲解详细 很细

    本文详细介绍了函数指针的三种主要用法:指向普通函数的指针、函数指针数组以及指向函数指针数组的指针。同时,还简单提及了在C++中函数指针与类成员的关联。 1. 指向普通函数的指针: 在C++中,函数指针的定义...

    函数指针详解[文].pdf

    本文详细介绍了函数指针在C++中的应用和使用,包括基本概念、函数指针数组以及指向函数指针数组的指针,并简要提及了函数指针与类成员的关联。 1. **基本的函数指针** 在C++中,函数可以被视为一等公民,它们可以...

    指针函数和函数指针变量

    在C语言中,指针和函数是两个非常重要的概念,而将它们结合在一起,就产生了指针函数和函数指针变量。这两个概念是C语言高级特性的体现,它们在编程中有着广泛的应用,如回调函数、动态加载库、内存管理等。 首先,...

    函数指针和函数对象

    函数指针是指向函数的指针变量,可以指向全局函数或类成员函数。函数指针的类型是指针类型,例如`typedef void (*fp)(int);`,其中`fp`是函数指针的名称,`(*fp)`表示函数指针指向的函数,`(int)`表示函数的参数类型...

    指向指针的指针.docx

    函数指针可以被用来存储函数的地址,而指向函数指针的指针则可以用来动态地改变程序的行为。例如,在提供的代码示例中,`p`就是一个函数指针,它指向`add`函数,可以通过改变`p`指向的函数来改变程序的行为。 ### 3...

    C语言指针函数和函数指针详细介绍.

    函数指针是指向函数的指针,包含了函数的地址,可以通过它来调用函数。其声明格式为:类型说明符 (*函数名)(参数)。例如: ```c void (*fptr)(); ``` 函数指针的声明笔削和它指向函数的声明保持一致。如果没有圆括号...

    函数指针和指针函数的区别

    2. **类型**:函数指针是一种特殊的指针类型,它指向函数而不是数据。指针函数是一个普通的函数,只是返回值是另一个类型的指针。 3. **操作**:函数指针可以被传递给其他函数作为参数,也可以作为其他函数的返回值...

    一般函数指针和类的成员函数指针

    在这个例子中,`pFun`是一个函数指针类型,它可以指向任何接受两个整型参数并返回一个整型值的函数。接下来,可以通过将函数的地址赋值给该函数指针来使用它: ```cpp pFun fun = Max; int result = (*fun)(3, 4); ...

    详解函数指针和指针函数

    函数指针的定义包含了函数的返回类型和参数列表,以确保与所指向的函数匹配。 1. **函数指针定义**:函数指针的声明语法是`函数类型 (*指针变量名)(形参列表)`。这里的`函数类型`指函数的返回类型,`*指针变量名`是...

    C++ 一般(普通)函数指针、类成员函数指针,用法区别,以及强制转换

    例如,如果你有一个接受两个整数并返回整数的函数`add(int a, int b)`,你可以定义一个指向它的函数指针如下: ```cpp int (*add_ptr)(int, int); ``` 然后你可以通过`= &add`将函数地址赋值给这个指针,并通过`*...

    指针进阶之函数指针和函数指针数组

    函数指针是指向函数的指针,它可以用来存放函数的地址,并且可以通过函数指针来调用函数。函数指针的定义方式与数组指针类似,但函数指针的类型是指向函数的类型。 2. 回忆函数 回忆一下我们之前说的函数,写一个...

    彻底理解指针,指针数组和数组指针,指针函数和函数指针

    ### 彻底理解指针,指针数组和数组指针,指针函数和函数指针 #### 一、基础知识 在计算机编程中,指针是一个非常重要的概念,尤其是在C/C++这样的语言中更是如此。简单来说,指针是一种变量,但它存储的不是普通的...

    函数指针和指针函数的理解

    **函数指针**指的是指向函数的指针变量,它存储的是函数的入口地址。当我们想要在运行时动态地选择调用哪个函数时,函数指针就显得非常有用。例如,我们可以将函数指针作为参数传递给其他函数,这样可以在运行时决定...

    C++对象和指针的引用

    &lt;类型说明符&gt;*&lt;指向函数指针名&gt;(&lt;参数表&gt;) 关于给指向函数的指针赋值的格式如下: &lt;指向函数的指针名&gt;=&lt;函数名&gt; 关于在程序中,使用指向函数的指针调用函数的格式如下: (*&lt;指向函数的指针名&gt;)(&lt;实参表&gt;) ...

    函数指针和指针函数,const的用法,指针常量,常量指针的用法

    ### 函数指针和指针函数的区分及应用 #### 函数指针的理解与使用 **函数指针**是一种特殊的指针类型,它可以用来存储函数的地址,进而通过该指针来调用函数。理解函数指针的关键在于认识到函数也是一种具有特定...

Global site tag (gtag.js) - Google Analytics