大话 函数指针 和 指针函数

一:起因

1)指针函数是指带指针的函数,即本质是一个函数。函数返回类型是某一类型的指针,即我们常见的函数类型,且返回值是指针。

(2)函数指针是指向函数的指针变量,即本质是一个指针变量,是一个指向函数(可能是代码区)的首地址的指针,正如我们都知道,数组名就是指向数组第一个元素的常量指针(详见《数组拾遗》)。同理,对于一个函数而言,函数名也是指向函数第一条指令的常量指针。而编译器要做的就是在程序编译之后,为每个函数分配一个首地址,即该函数第一条指令的地址。一般情况下,我们可以用一个指针来保存这个地址,而这个指针就是函数指针,该指针可以看作是它指向函数的别名,所以我们可以用该指针来调用这个函数。

(3)对指针的应用是C语言编程的精髓所在,而回调函数就是C语言里面对函数指针的高级应用。简而言之,回调函数是一个通过函数指针调用的函数。如果你把函数指针(函数的入口地址)传递给另一个函数,当这个函数指针被用来调用它所指向的函数时,我们就说这个函数是回调函数。

(4)我们非常熟悉的,而且经常用到的可能就是sort(begin,end)函数和 sort(begin,end,cmp);其中cmp正事函数名(即像数组名一样代表函数的首地址):

bool cmp(void const *a,void const *b)
{
	return *((int *)a) > *((int *)b);
}

注意强制类型转换,比较函数的参数必须被声明为void *以匹配查找函数的原型,然后强制转换为(int *)类型用于比较整型。然后把一个指向这个函数的指针作为参数传递给查找函数,查找函数调用这个比较函数来执行比较,采用这个方法,任何类型的值得都可以进行比较。

(5)注意指针函数与函数指针表示方法的不同,千万不要混淆。最简单的辨别方式就是看函数名前面的指针*号有没有被括号()包含,如果被包含就是函数指针,反之则是指针函数。

二:详细分析

(1)指针函数是指带指针的函数,即本质是一个函数。函数返回类型是某一类型的指针

 类型标识符   *函数名(参数表)

 int *f(x,y);

首先它是一个函数,只不过这个函数的返回值是一个地址值。函数返回值必须用同类型的指针变量来接受,也就是说,指针函数一定有函数返回值,而且,在主调函数中,函数返回值必须赋给同类型的指针变量。例如:

float *fun();

float *p;

p = fun(a);

(2)函数指针是指向函数的指针变量,即本质是一个指针变量。

int (*f) (int x); /* 声明一个函数指针 */

f=func; /* 将func函数的首地址赋给指针f */
其实这里不能称为函数名,应该叫做指针的变量名。这个特殊的指针指向一个返回整型值的函数指针的声明笔削和它指向函数的声明保持一致。
指针名和指针运算符外面的括号改变了默认的运算符优先级。如果没有圆括号,就变成了一个返回整型指针的函数的原型声明。例如:
 void (*fptr)();
 
把函数的地址赋值给函数指针,可以采用下面两种形式:
 fptr=&Function;
 fptr=Function; //
建议用这种方式
 
取地址运算符&不是必需的,因为单单一个函数标识符就标号表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。
 可以采用如下两种方式来通过指针调用函数:
  x=(*fptr)();
  x=fptr();//
建议用这种方式

(3)易混淆的地方:

函数指针的定义:

type (*func)(type&,type &)  或者 type (*func)(type ,type)

该语句声明了一个指针func,它指向了一个函数,这个函数带有了2个type型参数并返回一个type的值。(p.s. type类型可以被看成是int或者是floast等C++的类型)。 

A:一个指向函数的指针必须确保该函数被定义且分配了内存,否则它将指向一个空地址,这个可是大忌!

B: 特别注意第一个括号的位置。如果我们不写括号,如下:

type *func(type ,type)

这就不是一个指向函数的指针了,而是声明了一个函数,该函数返回一个type类型的指针

有了指向函数的指针变量后,可用该指针变量调用函数,就如同用指针变量可引用其他类型变量一样,在这些概念上是大体一致的.函数指针有两个用途:调用函数和做函数的参数。

4 注意指针函数与函数指针表示方法的不同,千万不要混淆。最简单的辨别方式就是看函数名前面的指针 * 号有没有被括号()包含,如果被包含就是函数指针,反之则是指针函数。

 三:函数指针的高级应用---- 作为函数的参数

(1)下面程序中,给出了三种不同类型的函数指针,分别用(1)(2)(3)做了标注区分;分为声明部分,实现部分,调用部分。

(2)代码

#include 
using namespace std;

void my_swap(int &,int &);// (4)普通函数的声明
int my_min(int,int);// (5)普通函数的声明
void my_input(void (*func)(int &,int &));//(1) 带有函数指针参数的声明
void my_input(int (*func)(int,int));// (2)带有函数指针参数的声明
void my_print(int,int,int (*func)(int,int));// (3)带有函数指针参数的声明
int main()
{
    cout << "please input two numbers:" << endl;
    my_input(my_swap);//(1) 带有函数指针参数的调用,函数名即为函数代码区的首地址
    my_input(my_min);// (2)带有函数指针参数的调用,函数名即为函数代码区的首地址
    int a,b;
    cin >> a >> b;
    my_print(a,b,my_min);// (3)带有函数指针参数的调用,函数名即为函数代码区的首地址
    return 0;
}
void my_input(void (*func)(int &,int&))// (1)带有函数指针参数的实现
{
    int a,b;
    cin >> a >> b;
    func(a,b);// 指针指向的函数代码区的首地址
    cout << a  << ",,," << b << endl;
}
void my_input(int (*func)(int,int))// (2)带有函数指针参数的实现
{
    int a,b;
    cin >> a >> b;
    int mi = func(a,b);// 指针指向的函数代码区的首地址
    cout << "a,,,b:" << mi << endl;
}
void my_print(int a,int b,int (*func)(int,int))// (3)带有函数指针参数的实现
{
    int mi = func(a,b);// 指针指向的函数代码区的首地址
    cout << a << ",," << b << ",," << mi << endl;
}
int my_min(int a,int b)// (5)
{
    return a


你可能感兴趣的:(c/c++成长之路,函数指针,指针函数,回掉函数)