冰冻三尺,非一日之寒。
前言
指针函数,函数指针,指针数组,数组指针。这些个概念,感觉一直都是迷迷糊糊的不是特别的明白。最近因为在做SYC的C语言,发现后面的题,基本上都是指针指过来指过去的,就索性用了一晚上来弄这个东西。记录一下,以便以后遗忘还可以再看。
指针函数
什么是指针函数
指针函数 : 返回值是指针的函数
指针函数本质是一个函数,函数返回类型是某一类型的指针。
指针函数怎么定义
类型标识符 *函数名(参数表)
int *f(int x,int y)
()优先级高,先与f结合成为一个函数,再由int *说明一个这是一个整型的指针函数。
使用
快速入门
这个使用法,我是这样理解的,因为这个函数是有返回值的,返回值的类型是一个地址,那么用的时候,就应该是这样。
float *fun(int x);//指针函数
float *p;//定义的一个指针
p = fun(a);//fun(a)是一个地址值,因为定义上他是一个指针函数,那么,它的返回值就是一个地址
实现
#include <stdio.h>
float *search(float (*pointer)[4], int n);//数组指针可以看下一章
int main(void)
{
float score[][4]={{60,70,80,90},{56,89,67,88},{34,78,90,66}};
float *p;
int i, m;
printf("enter the number of student:");
scanf("%d", &m);
printf("The scores of No. %d are:\n",m);
p=search(score, m);//这里就是指针函数的应用,返回的就是一个地址
for (i = 0; i < 4; i++)
{
printf("%5.2f\t", *(p + i)); //*(p + i),第m行第i列的元素值(m和i都从0编号)
}
printf("\n");
return 0;
}
float *search(float (*pointer)[4], int n)
{
float * pt;
pt = *(pointer + n); //将第n行第0列的地址给pt,以供返回
return (pt);//这里返回的就是一个地址
}
函数指针
什么是函数指针
函数指针 : 指向函数的指针
函数指针本质是一个指针变量,是指向函数的指针变量
函数指针怎么定义
类型说明符 (* 指针变量名(函数名)) (参数)
int (*f)(int a, int b);
()运算符,自左至右,首先说明f是一个指针,指向一个返回值是整型的函数。
使用
快速入门
int (*f) (int x); /*声明一个函数指针 */
f=func; /* 将func函数的首地址赋给指针f */
指向函数的指针包含了函数的地址的入口地址,可以通过它来调用函数。
这个特殊的指针指向一个返回整型值的函数。指针的声明必须和它指向函数的声明保持一致。
指针名和指针运算符外面的括号改变了默认的运算符优先级。如果没有圆括号,就变成了一个返回整型指针的函数的原型声明。
实现
案例1
#include <stdio.h>
int max(int x,int y)
{
return (x>y ? x : y);
}
int main(void)
{
int (*p)(int ,int);//函数指针:数据类型标志符 (指针变量名)(形参列表)
int a,b,c;
p=max; //将max函数的首地址给指针f
scanf("%d%d",&a,&b);
c=(*p)(a,b); //指针进行调用函数
printf("a=%d,b=%d,max=%d\n",a,b,c);
return 0;
}
/*这里p指的是一个指针变量,不像函数名字,他可以指向任何函数*/
p变量里面存放了max函数的地址。*p
,此时,就相当于是取这个函数了(可以这么去理解),用来进行调用函数了。相当于是p存放了max这个函数的地址,在用指针去调用函数max时,需要写成(
*p
)这个样子
案例2
代码
下面的这个案例来说明一下上面这个问题
#include <stdio.h>
int asdf(int a)
{
printf("%d\n",a);
return 0;
}
int main(void)
{
int (*p)(int);
asdf(5); //通过函数名调用函数
p=asdf; //将asdf函数的首地址给指针p
(*p)(5); //调用函数asdf
p(5); //调用函数asdf
printf("asdf is %d,p is %d,*p is %d\n",asdf,p,*p);
return 0;
}
输出:
5
5
5
asdf is 4198410,p is 4198410,*p is 4198410
解释
1.通过函数名调用函数和通过函数指针调用函数的区别
答:
1) 通过函数名调用函数
eg:asdf(5);
步骤:
根据已知函数地址调用对应函数。
2) 函数指针调用函数
eg:(*p)(5);
1.从指针中读取函数入口地址。
2.调用对应函数。
它们之间的区别一句话概括,那就是函数名是入口地址的代号,只在编译时发挥作用(等价于一个固定地址,所以函数名不能被赋值),函数指针在执行期发挥作用(指针值可以变化,可以赋值。所以(*p)(5)与asdf(5)等价
2.为什么(*p)(5)与p(5)结果相等
利用函数指针进行调用:
(*p)()
p()
很久很久以前C语言只允许前者,后来大家觉得这么写太麻烦就规定了后者能达到同样效果。后者在编译时和前者做相同的事情。它只是语法上的便利,本质上是一样的.
类似的语法上的便利还有:
p->h 通过指针访问结构成员,等价于 (p).h
p[n] 通过指针访问数组元素等价于 (p+n)
案例三
/* 函数指针的使用示例
在下面的例子中,着重学习如何通过fun函数中的第三个参数来实现对加减乘等操作的处理。
需要注意以下几点:
1. fun函数中第三个形参,函数指针的书写格式int (*p)(int, int)和使用格式(*p)(x, y)
2. 在调用fun函数时,送入的实参可以有两种形式。
A. 函数指针作为实参——注意ppp的定义格式 int (*ppp)(int, int);
ppp的赋值写法 ppp= max; 注意,没有括号!没有形参表!此处是将max函数在程序代码区中存储的首地址赋给ppp,并不是函数调用!
ppp作为实参的写法 fun(a, b, ppp) 没有括号,没有形参表!此处,fun的第三个参数ppp就是一个地址
B. 函数名称作为实参——注意书写格式 fun(a, b, add);
在C语言中,函数名字本身,和数组名称类似,代表了其在内存中存储的首地址
*/
#include <stdio.h>
int fun(int x, int y, int (*p)(int, int));
int max(int x, int y);
int min(int x, int y);
int add(int x, int y);
int main(void)
{
int a = 34, b = 22, result;
char n;
int (*ppp)(int, int);
ppp= NULL;
printf("请选择:1.求大值,2.求小值,3.求和:");
n = getchar();
switch(n)
{
case '1':
ppp= max;
result = fun(a, b, ppp);
break;
case '2':
result = fun(a, b, min);
break;
case '3':
result = fun(a, b, add);
break;
default:
printf("选择错误!\n");
}
printf("%d\n", result);
return 0;
}
int fun(int x, int y, int (*p)(int, int)) //第三个参数需要一个指针p,该参数p是一个函数指针,是专门指向“有2个int型形参且返回int的这类函数”的指针
{
int result;
result = (*p)(x, y); //注意书写格式! 调用该类(int XXX(int, int))函数所需要的实参,往往都是通过“外壳”函数fun的形参x和y传进来~~
return result;
}
/*
注意!函数指针往往出现在当多个函数的函数类型相同的情况下!
需要注意的是,如果max,min和add函数的类型不是 int XXX(int, int)这种类型,则不能作为fun函数的第三个参数,而
fun函数如果不能将多个子函数进行整合,则fun函数将失去其存在的意义!
*/
int max(int x, int y)
{
printf("大值是:");
return x > y ? x : y;
}
int min(int x, int y)
{
printf("小值是:");
return x > y ? y : x;
}
int add(int x, int y)
{
printf("和值是:");
return x + y;
}
后记
洋洋洒洒的总结了那么多,终于有一种恍然大悟的感觉了,再想一下。
函数指针:指向函数的指针,可以通过这个指针调用函数,前提是要把这个函数的地址传给指针,再调用函数(*指针变量名)
指针函数:返回值是指针类型的函数。因为返回的是一个地址,通常可以和数组结合一下。比如返回某一数组元素的地址。(由于返回的是地址,就直接函数名(形参)用就可以了)