除了void类型的函数之外,函数在调用结束之后都要有返回值,指针也可以是函数的返回值。当一个函数的返回值是指针类型时,这个函数就是指针型函数。 使用指针型函数的最主要目的就是要在函数结束时把大量的数据从被调函数返回到主调函数中。而通常非指针型函数调用结束后,只能返回一个变量或对象。
1.指针函数
除了void类型的函数之外,函数在调用结束之后都要有返回值,指针也可以是函数的返回值。当一个函数的返回值是指针类型时,这个函数就是指针型函数。 使用指针型函数的最主要目的就是要在函数结束时把大量的数据从被调函数返回到主调函数中。而通常非指针型函数调用结束后,只能返回一个变量或对象。
指针函数的一般定义形式是:
数据类型 *函数名(参数表)
{
函数体
}
数据类型表明函数返回指针的类型;函数名和“*”标识了一个指针型函数;参数表中是函数的形参列表。
【例】
int* fun(int size)
{
int* arr = (int*)malloc(size*sizeof(int));
return arr;
}
int main()
{
int* p = fun(5);
if (*p != NULL)
{
for (int i = 0; i < 5; i++)
{
p[i] = i + 1;
cout << p[i] <<" ";
}
cout << endl;
}
free(p);
return 0;
}
运行结果:
2.函数指针
在程序运行时,不仅数据要占据内存空间,执行程序的代码也被调入内存空间并占据一定的空间。**每一个函数都有函数名,实际上这个函数名就表示函数的代码在内存中的起始地址。**由此看来,调用函数的通常形式“函数名(参数表)”的实质就是“函数代码首地址(参数表)”。
函数指针就是专门用来存放函数代码首地址的变量。 在程序中可以像使用函数名一样使用指向函数的指针来调用函数。也就是说一旦函数指针指向了某个函数,它与函数名便具有同样的作用。函数名在表示函数代码起始地址的同时,也包括函数的返回值类型和参数的个数、类型、排列次序等信息。因此在通过函数名调用函数时,编译系统能够自动检查实参与形参是否相符,用函数的返回值参与其他运算时,能自动进行类型一致性检查。
(1)声明一个函数指针
声明一个函数指针时,也需要说明函数的返回值、形参列表,其一般语法如下:
数据类型 (*函数指针名)(形参表)
数据类型说明函数指针所指函数的返回值类型;第一个圆括号中的内容指明一个函数指针的名称;形参表则列出了该指针所指函数的形参类型和个数。
【注意】 由于对函数指针的定义在形式上比较复杂,如果在程序中出现多个这样的定义,多次重复这样的定义会相当繁琐,一个很好的解决办法就是typedef。
例如:
typedef int(*fun)(double);
这声明了fun为“有一个double形参、返回类型为int的函数的指针”类型的别名。下面,需要声明这一类型的变量时,可以直接使用:
fun funprt;
这声明了一个具有该类型的名称为funptr的函数指针。用typedef可以方便地为复杂类型起别名。
(2)函数指针的使用
函数指针在使用之前也要进行赋值,是指针指向一个已经存在的函数代码的起始地址。一般语法为:
函数指针名=函数名;
等号右边的函数名所指出的必须是一个已经声明过的、和函数指针具有相同的返回类型和相同形参表的函数。在赋值之后,就可以通过函数指针名来直接引用这个指针指向的函数。
【例】函数指针实例
void A(float)
{
cout << "这是一个A函数" << endl;
}
void B(float b)
{
cout << "b的值为:" << b << endl;
}
void C(float c)
{
cout << "c的值为:" << c << endl;
}
const float PI = 3.14159f;
const float TOW_PI = PI * 2.0f;
int main()
{
void (*fun)(float);//函数指针
A(PI);
fun = A;//函数指针指向A
fun(PI);//函数指针调用
fun = B;//函数指针指向B
fun(TOW_PI);//函数在指针调用
fun(13.0);//函数指针调用
fun = C;//函数指针指向C
C(PI);//函数指针调用
return 0;
}
运行结果:
上例程序中声明了一个void类型的函数指针:
void (*fun)(float);//void类型的函数指针
在主函数运行过程中,通过赋值语句使这个指针分别指向函数A,B和C,然后通过函数指针来实现对函数的调用。