您的位置:首页 > 编程语言 > C语言/C++

非典型性C语言教程-1.5 函数指针

2007-07-15 16:03 344 查看
函数指针是非常重要的概念,后来的对象概念都依赖与函数指针的概念,比如C++对象的虚函数指针表,比如Java的接口,比如.Net的委托机制。

函数指针就是函数的入口地址。它的定义形式如下:
int (*pfun)(int);
这里定义了一个函数指针叫pfun,它指向的函数应该是有一个惨呼类型int,返回值是int。虽然C语言的函数指针可能带类型信息,但是这个类型信息没有什么很大用处,实际上整个C语言都没有什么类型信息,你可以在运行时很简单的改变C语言的类型信息。比如函数指针:
int (*pfun)(int);
你 可以把它指向标准函数printf。显然printf的函数类型是int (*printf)(char*,...);而不是int(*pfun)(int);。C语言不会帮你进行类型检查,但是如果你把指针pfun指向 printf,然后通过pfun来调用printf会是一个未定义行为,未定义一般意味着程序崩溃。

这么定义函数指针的语法有点麻烦,当函数的申明很复杂时,会定义出一个很难看懂的东西,比如:
int* (*(*pfun)(int*))(int*);
这种定义就让人难以理解。合理的运用C语言的typedef特性就可以让函数指针的定义变得明确,提高代码的可读性。比如上面的定义我们首先定义:
typedef int* (*PFUN_1)(int*);
这样我们就定义了一个别名PFUN_1,PFUN_1是一个函数指针的类型,这种函数指针指向的函数有一个参数是int*,返回类型是int*。这样:
int* (*(*pfun)(int*))(int*);
就可以简化为:
PFUN_1 (*pfun)(int*);
即一个函数指针pfun它指向的函数的返回类型是一个PFUN_1,函数的参数是一个int*。同理可以进一步简化,定义typedef:
typedef PFUN_1 (*PFUN_2)(int*);
然后把pfun的定义简化为
PFUN_2 pfun;
Unix 中系统调用signal,就是一个参数是函数指针,返回值是函数指针的函数,它的定义就比较难懂。在Windows中动态加载DLL的API函数 GetProcAddress返回的也是一个函数指针,通常需要定义一个typedef,不然使用GetProcAddress的代码也是晦涩难懂。

使用函数指针就和使用函数基本是一样的。比如
pfun(&a);
为什么要用函数指针能,函数指针主要的用途就在OO编程中的多态。C++是OO语言,C语言不是,但是用C可以实现多态,C++实现多态的原理也是C的函数指针。

举个例子,C语言的标准库中有一个函数qsort。这个函数的申明是:
void qsort(
void *base,
size_t num,
size_t width,
int (__cdecl *compare )(const void *, const void *)
);


大家知道C语言是没有重载和模板机制的,如果你要写一个求两个数字中大的一个的函数,你必须写一个
double max(double x, double y)
{
return x>y?x:y;
}


short,char,int等类型都可以自动转换成double。但是如果你需要一个自定义的复数类型
struct complex
{
double real;
double img;
}


上 面这个函数就不好用了。排序函数也是一样,标准排序函数大部分内容都是一样的,选出枢轴,比较交换,递归,但是不同的数据元素有不同的比较方法。比如刚才 的复数,简单的用关系运算符就无法比较。为了写一个通用的快速排序版本,标准库的作者用了两个技巧。第一个就是void类型的指针,void类型可以指向 任何内存地址,只要参数width给出指向一个数据元素的大小就可以了。第二个就是函数指针int (__cdecl *compare )(const void *, const void *),对于你自己定义的复合类型,你需要定义一个函数来进行比较,然后把这个函数通过指针的形式告诉标准库函数qsort,qsort就知道如何对数据类 型排序了。

比如现在我有一个复合类型struct complex的数组struct complex cAarray[100];我需要将它按模的大小排序。首先我要定义函数compare:

int compare (const void * _l, const void * _r)
{
struct complex* pl=_l;
struct complex* pr=_r;
double ml=  pl.real*pl.real+pl.img*pl.img;
double mr=  pr.real*pr.real+pr.img*pr.img;
if(ml>mr)return 1;
if(ml==mr)return 0;
if(ml


然后调用函数qsort:
qort(cArray, 100, sizoef(struct complex), compare );

实际上函数指针可以更改另一个函数的行为,这是它最重要的作用。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息