一.什么是函数指针
首先用函数指针变量调用函数
一个函数,在编译的时候,系统会给这个函数分配一个入口地址,这个入口地址就称为函数的指针(地址),既然有地址,我们可以定义一个指针变量,指向该函数,然后通过该指针变量调用该函数
代码语言:javascript复制int max(int a, int b)
{
if(a < b)
return b;
return a;
}
int a = max(10 ,20);
cout << a << endl;
这是正常的函数调用,现在用函数指针看看
代码语言:javascript复制int (*p)(int x, int y); //定义一个函数指针变量
p = max;
int a = (*p)(10, 20);//调用*p就是调用函数max,p指向函数max的入口,等价于a = max(10,20),这里的调用只是用*p取代了函数名,p不能指向函数中间的某条语句,所以*(p 1)不合法,其实这里的(*p)的*是可以省略的,比如a = p(10, 20)
cout << a << endl;
对比一下
代码语言:javascript复制原来是
int max(int a, int b)
现在是
int (*p)(int x, int y);
相当于max 替换成(*p)
原来调用是
max(10, 20)
现在是
(*p)(10, 20);
记得
代码语言:javascript复制int (*p)(int x, int y);
不能写成
代码语言:javascript复制int *p(int x, int y);
因为括号优先级比*的优先级要高,如果这样写的话,这就是函数说明了,这里的int *就表示这个函数的返回值是指向整型变量的指针
所以*p两侧的括号不可以省略,有括号表示*和p先结合代表一个指针变量,然后再和后面的括号结合表示此指针变量指向函数
当然这个可以写的简单一些
代码语言:javascript复制int (*p)(int x, int y);
可以写成
int (*p)(int, int);
像上面写的
代码语言:javascript复制p = max
将函数max的入口地址赋给指针变量p,函数名代表函数的入口地址,现在p就是指向函数max的指针变量,p和max都指向函数的开头
或者这样写也行
代码语言:javascript复制p = &max
p = max和p = &max是一样的
还有就是调用的时候,可以等价写
就是a=(*p)(10, 20)和a = p(10, 20)等价
其实如果真的调试程序的话,你看p=max这个,发现max是一个地址,p是一个地址
但其实真正函数的地址是p显示的,因为VS内部对函数有一些处理手段,会有一张表,max显示的地址只不过是表里的地址而已
但你如果输出p和max,发现他们两个是一样的,都是p显示的地址,也就是函数真正的地址
总结下
a)函数指针的一般形式:
数据类型标识符 (*指针变量名)(形参列表) 比如:int (*p)(int x, int y);
其中数据类型标识符就是指函数的返回值类型,形参列表里可以只有类型说明符,多个类型说明符之间用逗号分隔
我们可以通过函数指针指向不同的函数,来达到调用不同函数的目的,这个是有实际用途的
b)函数的调用,可以通过函数名,也可以通过函数指针调用:max(10, 20)和(*p)(10, 20);
c)对指向函数的指针变量p,做一些像p ,p–,p n等运算都不可,也没有意义
二.把指向函数的指针变量作为函数参数
指向函数的指针变量也可以作为另外一个函数FuncB的参数,从而实现函数地址的传递,也就是在FuncB函数中调用该函数指针变量所指向的函数的目的
代码语言:javascript复制int max(int a, int b)
{
if(a < b)
return b;
return a;
}
int wwmax(int x, int y, int (*p)(int x, int y))
{
int result = p(x, y);
return result;
}
或者把wwmax这样写
int wwmax(
int x,
int y,
int (*p)(int x, int y) //形参就是一个函数指针
)
{
int result = p(x, y);调用函数指针p所指向的函数
return result;
}
int main()
{
int c;
c = wwmax(1, 2, max);
int (*midFunc)(int, int);
midFunc = max;
c = wwmax(1, 2, midFunc);
//这三行代码和c = wwmax(1, 2, max);效果是一样的,因为midFunc就是max
}
那有人会问为什么我们不能在wwmax直接调用max函数呢,而要用函数指针
原因是这样滴,看代码
代码语言:javascript复制int max(int a, int b)
{
if(a < b)
return b;
return a;
}
int min(int a, int b)
{
if(a < b)
return a;
return b;
}
int wwmax(
int x,
int y,
int (*p)(int x, int y) //形参就是一个函数指针
)
{
int result = p(x, y);调用函数指针p所指向的函数
return result;
}
int main()
{
int c;
c = wwmax(1, 2, max);
c = wwmax(1, 2, min);
}
如果我们有min函数,那我们如果像刚才说的,直接在wwmax里面调用max函数,那有了min的话,不得还在wwmax里面修改嘛,修改或者添加一个min,这个也太费事了
而写成函数指针的形式来调用,你看我们wwmax代码不用改,直接在调用的时候传就可以c = wwmax(1, 2, min);
三.返回指针值的函数
一般的返回,是return; return 1;这种的
但是函数中也可以返回指针型数据,也就是地址
返回指针值的函数的一般定义形式:
数据类型 *函数名(参数列表): int *p(int x, int y);
其中p是函数名,()优先级高于*,因此p先和()结合,这就是函数形式,返回值为整型 指针
是不是有点熟悉,就是上面讲的
记得
代码语言:javascript复制int (*p)(int x, int y);
不能写成
代码语言:javascript复制int *p(int x, int y);
上面叫做,定义一个函数指针变量
下面叫做,返回指针值的函数
下面开始说例子
代码语言:javascript复制//返回指针值的函数
int *add(int x, int y)
{
int sum = x y;
return ∑
}
int main()
{
int *presult;
presult = add(4, 5);
cout << *presult << endl;
}
这样看是没有问题的,并且输出也正确,但这有个致命的问题
代码语言:javascript复制return ∑ //隐藏一个致命的问题,add函数调用完毕后,sum的内存会被系统回收
比如调试的时候会看到&sum内存是0x0041,但是add调用完后,其实这段内存已经不属于add了,这时候你去读这个内存虽然是正确的,能读出来是9,但其实这块内存已经不属于add了,这样读或者写是有风险的
所以绝对不可以把sum的内存地址返回到被调用函数中并加以使用
presult = add(4, 5);*presult;也就是在执行add后,presult指向的内存已经不归你所有,你不应该从中取得值或者给他赋值
那要怎么改呢,先简单说一种,剩下的以后再说
第一种方式,就是把sum改成全局变量,这个变量占用的内存一直存在,能被我控制,直到程序结束