指针函数和函数指针


冰冻三尺,非一日之寒。

前言

指针函数,函数指针,指针数组,数组指针。这些个概念,感觉一直都是迷迷糊糊的不是特别的明白。最近因为在做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;
}

后记

洋洋洒洒的总结了那么多,终于有一种恍然大悟的感觉了,再想一下。

函数指针:指向函数的指针,可以通过这个指针调用函数,前提是要把这个函数的地址传给指针,再调用函数(*指针变量名)

指针函数:返回值是指针类型的函数。因为返回的是一个地址,通常可以和数组结合一下。比如返回某一数组元素的地址。(由于返回的是地址,就直接函数名(形参)用就可以了)