前面我们探讨了数组指针和指针数组的概念,两者是那么纠结和模糊。与这概念很像,对比于函数指针和指针函数,迁移概念过来,道理还是一样的:
函数指针强调的是指针,而指针函数强调的是函数。
一、函数指针
前面好像也谈论过了,指针可以指向变量、数组,还可以指向函数。顾名思义,函数指针就是指向函数的指针。函数名实际上是程序在内存中起始地址。
指向函数的指针可以把地址传递给函数,也可以从函数返回给指向函数的指针。
实例1:(没有使用函数指针)
/*通过一个函数求两个数的和(通过函数指针调用该函数)*/
#include <stdio.h>
int Sum(int a,int b);//声明求和函数
void main()
{
int a,b;
printf("请您输入两个整数:");
scanf("%d,%d",&a,&b);
Sum(a,b);
}
int Sum(int a,int b)
{
int sum=a+b;
printf("%d与%d之和是:%d\n",a,b,sum);
return sum;
}
实例2:(使用函数指针)
/*通过一个函数求两个数的和(通过函数指针调用该函数)*/
#include <stdio.h>
int Sum(int a,int b);//声明求和函数
void main()
{
int a,b;
int (*fun)(int,int);
printf("请您输入两个整数:");
scanf("%d,%d",&a,&b);
printf("************第一种:直接函数名调用求和函数**********");
printf("%d+%d=%d\n",a,b,Sum(a,b));
fun=Sum;
printf("************第二种:函数指针调用求和函数************");
printf("%d+%d=%d\n",a,b,(*fun)(a,b));
}
int Sum(int x,int y)
{
int sum=x+y;
printf("%d与%d之和是:%d\n",x,y,sum);
return sum;
}
以上程序中,int (*fun)(int,int);是声明一个指向函数的指针变量,并且说指向的函数返回值是整形,有两个整型参数。由于*运算符的优先级比()运算符高,所以()不可以省略。
语句fun=Sum;表示函数指针fun指向函数Sum,fun和Sum都指向函数Sum的起始地址,程序在编译阶段会翻译成一行行指令并被装入到内存区域中。
注意一点就是:(*fun)(a,b);是执行调用求和函数的,也可以写成fun(a,b)的形式,因为函数本身就是一个地址。当然,函数指针还可以作为指针传递给其他函数。
实例3:声明一个指向函数的指针数组,并通过指针调用函数的应用。
#include <stdio.h>
void f1();
void f2();
void f3();
void main()
{
void (*f[3])()={f1,f2,f3};//定义了一个指向函数的指针数组的声明
int flag;
printf("请输入一个1,2,或者3.输入0退出.\n");
scanf("%d",&flag);
while(flag)
{
if(flag==1||flag==2||flag==3)
{
f[flag-1]();//通过函数指针调用数组中的函数
printf("请输入一个1,2,或者3.输入0退出.\n");
scanf("%d",&flag);
}
else
{
printf("请输入一个合法的数(1-3),0退出.\n");
scanf("%d",&flag);
}
}
printf("程序退出.\n");
}
void f1()
{
printf("函数f1被调用!\n");
}
void f2()
{
printf("函数f2被调用!\n");
}
void f3()
{
printf("函数f3被调用!\n");
}
二、指针函数
指针函数侧重于函数,其函数的返回值是指针类型的函数。指针函数的定义形式可以为如下格式:float* fun(int a,int b);
其中fun是函数名,前面的“*”号说明返回值的类型是指针类型,因为前面的类型标识是float,所以返回的指针指向浮点型。
来颗栗子:(本栗子源自陈锐编著的《跟我学数据结构》p41例子)
#include <stdio.h>
int *FindAddress(int (*ptr)[4],int n);//声明查找成绩行地址函数
void Display(int a[][4],int n,int *p);//声明输入成绩函数
void main()
{
int row,n=4;
int *p;
int score[3][4]={{76,86,78,79},{89,82,85,90},{88,75,86,82}};
printf("请输入学生的编号(1或2或3).输入0退出程序.\n");
scanf("%d",&row);
while(row)
{
if(row==1||row==2||row==3)
{
printf("第%d个学生的成绩4门课成绩是:\n",row);
p=FindAddress(score,row-1);//调用指针函数
Display(score,n,p);
printf("请输入学生的编号(1或2或3).输入0退出程序.\n");
scanf("%d",&row);
}
else
{
printf("请输入学生的编号(1或2或3).输入0退出程序.\n");
scanf("%d",&row);
}
}
}
int* FindAddress(int (*ptrScore)[4],int n)
{
int *ptr;
ptr=*(ptrScore+n);
return ptr;
}
void Display(int a[][4],int n,int *p)
{
int col;
for(col=0;col<n;col++)
{
printf("%4d",*(p+col));//输出查找学生的每门课成绩
}
printf("\n");
}
在程序中,main()通过调用函数FindAddress(score,row-1);把二维数组的行地址传递给*FindAddress(int (*ptr)[4],int n)的形式参数ptrScore,执行语句ptr=*(ptrScore+n),然后返回行指针ptr,调用Display(score,n,p)输出成绩,p+col是改变列地址,即找到该学生成绩的每门课的位置,逐个输出每门课的成绩。
三、总结两者的区别:
注意指针函数与函数指针表示方法的不同,千万不要混淆。
最简单的辨别方式就是看函数名前面的指针*号有没有被括号()包含,如果被包含就是函数指针,反之则是指针函数。
(1)指针函数是指带指针的函数,即本质是一个函数。函数返回类型是某一类型的指针。
定义:类型标识符 *函数名(参数表)
栗子:int *f(x,y); float *fun();等价于:float *ptr;ptr=*fun(a);
首先它是一个函数,只不过这个函数的返回值是一个地址值。
函数返回值必须用同类型的指针变量来接受,也就是说,指针函数一定有函数返回值.而且,在主调函数中,函数返回值必须赋给同类型的指针变量。
指针函数:当一个函数声明其返回值为一个指针时,实际上就是返回一个地址给调用函数,以用于需要指针或地址的表达式中。
格式:类型说明符 * 函数名(参数)
(2) 函数指针是指向函数的指针变量,即本质是一个指针变量。
int (*f) (int x); /* 声明一个函数指针 */
f=func; /* 将func函数的首地址赋给指针f */
1) 指向函数的指针包含了函数的地址,可以通过它来调用函数。
格式:类型说明符 (*函数名)(参数)
其实这里不能称为函数名,应该叫做指针的变量名。这个特殊的指针指向一个返回整型值的函数。
2)指针名和指针运算符外面的括号改变了默认的运算符优先级。如果没有圆括号,就变成了一个返回整型指针的函数的原型声明。
例如:void (*fptr)();
3)把函数的地址赋值给函数指针,可以采用下面两种形式:
fptr=&Function;
fptr=Function;
3)取地址运算符&不是必需的,因为单单一个函数标识符就标号表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。
可以采用如下两种方式来通过指针调用函数:
x=(*fptr)();
x=fptr();
第二种格式看上去和函数调用无异。但是有些程序员倾向于使用第一种格式,因为它明确指出是通过指针而非函数名来调用函数的。
主要的区别是一个是指针变量,一个是函数。在使用是必要要搞清楚才能正确使用
❤永葆一颗纯洁、宽容平和、仁慈谦卑和意气风发的心!
态度决定一切 努力改变命运