精华内容
下载资源
问答
  • 指针函数函数指针

    万次阅读 多人点赞 2019-03-30 16:21:36
    很多人因为搞不清这两个概念,干脆就避而远之,我刚接触C语言的时候对这两个概念也比较模糊,特别是当指针函数函数指针函数指针变量、函数指针数组放在一块的时候,能把强迫症的人活活逼疯。 其实如果理解了这些...

    概述

    指针函数和函数指针是C语言里两个比较绕的概念。但是不仅面试题爱考,实际应用中也比较广泛。很多人因为搞不清这两个概念,干脆就避而远之,我刚接触C语言的时候对这两个概念也比较模糊,特别是当指针函数、函数指针、函数指针变量、函数指针数组放在一块的时候,能把强迫症的人活活逼疯。
    其实如果理解了这些概念的本质,是不需要死记硬背的,理解起来也比较容易。

    指针函数

    指针函数: 顾名思义,它的本质是一个函数,不过它的返回值是一个指针。其声明的形式如下所示:

    ret *func(args, ...);
    

    其中,func是一个函数,args是形参列表,ret *作为一个整体,是 func函数的返回值,是一个指针的形式。
    下面举一个具体的实例来做说明:

    文件:pointer_func.c

    # include <stdio.h>
    # include <stdlib.h>
    
    int * func_sum(int n)
    {
        if (n < 0)
        {
            printf("error:n must be > 0\n");
            exit(-1);
        }
        static int sum = 0;
        int *p = &sum;
        for (int i = 0; i < n; i++)
        {
            sum += i;
        }
        return p;
    }
    
    int main(void)
    {
        int num = 0;
        printf("please input one number:");
        scanf("%d", &num);
        int *p = func_sum(num); 
        printf("sum:%d\n", *p);
        return 0;
    }
    

    上例就是一个指针函数的例子,其中,int * func_sum(int n)就是一个指针函数, 其功能十分简单,是根据传入的参数n,来计算从0到n的所有自然数的和,其结果通过指针的形式返回给调用方。
    以上代码的运行结果如下所示:
    运行结果1
    如果上述代码使用普通的局部变量来实现,也是可以的,如下所示:

    文件:pointer_func2.c

    # include <stdio.h>
    # include <stdlib.h>
    
    int func_sum2(int n)
    {   
        if (n < 0)
        {   
            printf("error:n must be > 0\n");
            exit(-1);
        }
        int sum = 0;
        int i = 0;
        for (i = 0; i < n; i++)
        {   
            sum += i;
        }
        return sum;
    }
    
    int main(void)
    {
        int num = 0;
        printf("please input one number:");
        scanf("%d", &num);
        int ret = func_sum2(num);
        printf("sum2:%d\n", ret);
        return 0;
    }
    

    本案例中,func_sum2函数的功能与指针函数所实现的功能完全一样。
    在这里插入图片描述
    不过在使用指针函数时,需要注意一点,相信细心地读者已经发现了,对比func_sumfunc_sum2函数,除了返回值不一样之外,还有一个不同的地方在于,在func_sum中,变量sum使用的是静态局部变量,而func_sum2函数中,变量sum使用的则是普通的变量。
    如果我们把指针函数的sum定义为普通的局部变量,会是什么结果呢?不妨来试验一下:

    文件:pointer_func3.c

    # include <stdio.h>
    # include <stdlib.h>
    
    int * func_sum(int n)
    {
        if (n < 0)
        {
            printf("error:n must be > 0\n");
            exit(-1);
        }
        int sum = 0;
        int *p = &sum;
        for (int i = 0; i < n; i++)
        {
            sum += i;
        }
        return p;
    }
    
    int main(void)
    {
        int num = 0;
        printf("please input one number:");
        scanf("%d", &num);
        int *p = func_sum(num); 
        printf("sum:%d\n", *p);
        return 0;
    }
    

    执行以上程序,发现仍然能得到正确的结果:
    在这里插入图片描述
    可是如果我们把main函数里面稍微改动一下:

    int main(void)
    {
        int num = 0;
        printf("please input one number:");
        scanf("%d", &num);
        int *p = func_sum(num);
        printf("wait for a while...\n");    //此处加一句打印
        printf("sum:%d\n", *p);
        return 0;
    }
    

    我们在输出sum之前打印一句话,这时看到得到的结果完全不是我们预先想象的样子,得到的并不是我们想要的答案。
    在这里插入图片描述
    为什么会出现上面的结果呢?
    其实原因在于,一般的局部变量是存放于栈区的,当函数结束,栈区的变量就会释放掉,如果我们在函数内部定义一个变量,在使用一个指针去指向这个变量,当函数调用结束时,这个变量的空间就已经被释放,这时就算返回了该地址的指针,也不一定会得到正确的值。上面的示例中,在返回该指针后,立即访问,的确是得到了正确的结果,但这只是十分巧合的情况,如果我们等待一会儿再去访问该地址,很有可能该地址已经被其他的变量所占用,这时候得到的就不是我们想要的结果。甚至更严重的是,如果因此访问到了不可访问的内容,很有可能造成段错误等程序崩溃的情况。
    因此,在使用指针函数的时候,一定要避免出现返回局部变量指针的情况。
    那么为什么用了static就可以避免这个问题呢?
    原因是一旦使用了static去修饰变量,那么该变量就变成了静态变量。而静态变量是存放在数据段的,它的生命周期存在于整个程序运行期间,只要程序没有结束,该变量就会一直存在,所以该指针就能一直访问到该变量。
    因此,还有一种解决方案是使用全局变量,因为全局变量也是放在数据段的,但是并不推荐使用全局变量。

    函数指针

    与指针函数不同,函数指针 的本质是一个指针,该指针的地址指向了一个函数,所以它是指向函数的指针。
    我们知道,函数的定义是存在于代码段,因此,每个函数在代码段中,也有着自己的入口地址,函数指针就是指向代码段中函数入口地址的指针。
    其声明形式如下所示:

    ret (*p)(args, ...);
    

    其中,ret为返回值,*p作为一个整体,代表的是指向该函数的指针,args为形参列表。其中p被称为函数指针变量

    关于函数指针的初始化

    与数组类似,在数组中,数组名即代表着该数组的首地址,函数也是一样,函数名即是该数组的入口地址,因此,函数名就是该函数的函数指针。
    因此,我们可以采用如下的初始化方式:

    函数指针变量 =  函数名;
    

    下面还是以一个简单的例子来具体说明一下函数指针的应用:

    文件:func_pointer.c

    #include <stdio.h>
    
    int max(int a, int b)
    {
        return a > b ? a : b;
    }
    
    int main(void)
    {
        int (*p)(int, int); //函数指针的定义
        //int (*p)();       //函数指针的另一种定义方式,不过不建议使用
        //int (*p)(int a, int b);   //也可以使用这种方式定义函数指针
        
        p = max;    //函数指针初始化
    
        int ret = p(10, 15);    //函数指针的调用
        //int ret = (*max)(10,15);
        //int ret = (*p)(10,15);
        //以上两种写法与第一种写法是等价的,不过建议使用第一种方式
        printf("max = %d \n", ret);
        return 0;
    }
    

    上面这个函数的功能也十分简单,就是求两个数中较大的一个数。值得注意的是通过函数指针调用的方式。
    首先代码里提供了3种函数指针定义的方式,这三种方式都是正确的,比较推荐第一种和第三种定义方式。然后对函数指针进行初始化,前面已经提到过了,直接将函数名赋值给函数指针变量名即可。
    上述代码运行的结果如下:
    在这里插入图片描述
    调用的时候,既可以直接使用函数指针调用,也可以通过函数指针所指向的值去调用。(*p)所代表的就是函数指针所指向的值,也就是函数本身,这样调用自然不会有问题。有兴趣的同学可以去试一试。

    为什么要使用函数指针?

    那么,有不少人就觉得,本来很简单的函数调用,搞那么复杂干什么?其实在这样比较简单的代码实现中不容易看出来,当项目比较大,代码变得复杂了以后,函数指针就体现出了其优越性。
    举个例子,如果我们要实现数组的排序,我们知道,常用的数组排序方法有很多种,比如快排,插入排序,冒泡排序,选择排序等,如果不管内部实现,你会发现,除了函数名不一样之外,返回值,包括函数入参都是相同的,这时候如果要调用不同的排序方法,就可以使用指针函数来实现,我们只需要修改函数指针初始化的地方,而不需要去修改每个调用的地方(特别是当调用特别频繁的时候)。

    回调函数

    函数指针的一个非常典型的应用就是回调函数
    什么是回调函数?
    回调函数就是一个通过指针函数调用的函数。其将函数指针作为一个参数,传递给另一个函数。
    回调函数并不是由实现方直接调用,而是在特定的事件或条件发生时由另外一方来调用的。
    同样我们来看一个回调函数的例子:

    文件:callback.c

    #include<stdio.h>
    #include<stdlib.h>
    
    //函数功能:实现累加求和
    int func_sum(int n)
    {
            int sum = 0;
            if (n < 0)
            {
                    printf("n must be > 0\n");
                    exit(-1);
            }
            for (int i = 0; i < n; i++)
            {
                    sum += i;
            }
            return sum;
    }
    
    //这个函数是回调函数,其中第二个参数为一个函数指针,通过该函数指针来调用求和函数,并把结果返回给主调函数
    int callback(int n, int (*p)(int))
    {
            return p(n);
    }
    
    int main(void)
    {
            int n = 0;
            printf("please input number:");
            scanf("%d", &n);
            printf("the sum from 0 to %d is %d\n", n, callback(n, func_sum));       //此处直接调用回调函数,而不是直接调用func_sum函数
            return 0;
    }
    

    上面这个简单的demo就是一个比较典型的回调函数的例子。在这个程序中,回调函数callback无需关心func_sum是怎么实现的,只需要去调用即可。
    这样的好处就是,如果以后对求和函数有优化,比如新写了个func_sum2函数的实现,我们只需要在调用回调函数的地方将函数指针指向func_sum2即可,而无需去修改callback函数内部。
    以上代码的输出结果如下:
    在这里插入图片描述
    回调函数广泛用于开发场景中,比如信号函数、线程函数等,都使用到了回调函数的知识。

    展开全文
  • 其中,后缀运算符括号"()"表示这是一个函数,其前缀运算符星号"*"表示此函数指针函数,其函数值为指针,即它带回来的值的类型为指针,当调用这个函数后,将得到一个"指向返回值为…的指针(地址),"类型名"表示...

    转载自:https://www.cnblogs.com/yangjiquan/p/11465376.html

    首先说一下指针函数:

    1.指针函数的定义

        顾名思义,指针函数即返回指针的函数。其一般定义形式如下:

        类型名 *函数名(函数参数表列);

        其中,后缀运算符括号"()"表示这是一个函数,其前缀运算符星号"*"表示此函数为指针型函数,其函数值为指针,即它带回来的值的类型为指针,当调用这个函数后,将得到一个"指向返回值为…的指针(地址),"类型名"表示函数返回的指针指向的类型"。

        "(函数参数表列)"中的括号为函数调用运算符,在调用语句中,即使函数不带参数,其参数表的一对括号也不能省略。其示例如下:

     int *pfun(int, int);

        由于"*"的优先级低于"()"的优先级,因而pfun首先和后面的"()"结合,也就意味着,pfun是一个函数。即:

    int *(pfun(int, int));

        接着再和前面的"*"结合,说明这个函数的返回值是一个指针。由于前面还有一个int,也就是说,pfun是一个返回值为整型指针的函数。

        我们不妨来再看一看,指针函数与函数指针有什么区别?

    int (*pfun)(int, int);

        通过括号强行将pfun首先与"*"结合,也就意味着,pfun是一个指针,接着与后面的"()"结合,说明该指针指向的是一个函数,然后再与前面的int结合,也就是说,该函数的返回值是int。由此可见,pfun是一个指向返回值为int的函数的指针。

        虽然它们只有一个括号的差别,但是表示的意义却截然不同。函数指针的本身是一个指针,指针指向的是一个函数。指针函数的本身是一个函数,其函数的返回值是一个指针。

    2.    用函数指针作为函数的返回值

        在上面提到的指针函数里面,有这样一类函数,它们也返回指针型数据(地址),但是这个指针不是指向int、char之类的基本类型,而是指向函数。对于初学者,别说写出这样的函数声明,就是看到这样的写法也是一头雾水。比如,下面的语句:

    int (*ff(int))(int *, int);

    我们用上面介绍的方法分析一下,ff首先与后面的"()"结合,即:

     

    int (*(ff(int)))(int *, int);   // 用括号将ff(int)再括起来

    也就意味着,ff是一个函数。

        接着与前面的"*"结合,说明ff函数的返回值是一个指针。然后再与后面的"()"结合,也就是说,该指针指向的是一个函数。

    这种写法确实让人非常难懂,以至于一些初学者产生误解,认为写出别人看不懂的代码才能显示自己水平高。而事实上恰好相反,能否写出通俗易懂的代码是衡量程序员是否优秀的标准。一般来说,用typedef关键字会使该声明更简单易懂。在前面我们已经见过:

    int (*PF)(int *, int);

    也就是说,PF是一个函数指针"变量"。当使用typedef声明后,则PF就成为了一个函数指针"类型",即:

    typedef int (*PF)(int *, int);

    这样就定义了返回值的类型。然后,再用PF作为返回值来声明函数:

    PF ff(int);

     

    展开全文
  • C++中的指针、数组指针指针数组、函数指针指针函数 本文从初学者的角度,深入浅出地详解什么是指针、如何使用指针、如何定义指针、如何定义数组指针函数指针,并给出对应的实例演示;接着,区别了数组...

    C++中的指针、数组指针与指针数组、函数指针与指针函数



    本文从初学者的角度,深入浅出地详解什么是指针、如何使用指针、如何定义指针、如何定义数组指针和函数指针,并给出对应的实例演示;接着,区别了数组指针与指针数组、函数指针与指针函数;最后,对最常混淆的引用传递、值传递和指针传递做了区处。


    C++中一个重要的特性就是指针,指针不仅具有获得地址的能力,还具有操作地址的能力。指针可以用于数组、或作为函数的参数,用来访问内存和对内存的操作,指针的使用使得C++很高效,但是指针也非常危险,使用不当会带来比较严重的问题。


    1、指针


    程序中所有的变量和常量都存在一个内存地址中,当然,函数也有对应的内存地址,内存地址的不同会导致程序执行时有所不同。


    指针就是用来控制和存储内存地址的变量,它指向单个对象的地址,除了void之外,指针的数据类型与所指向地址的变量数据类型保持一致。


    2、如何定义指针、数组指针、函数指针


    常见的指针定义有3种:变量指针、数组指针和函数指针的定义。


    (1)、变量指针的定义


    int* p=0;	//定义指针p,并初始化指针为0,即指向的地址为0000 0000
    或
    int a=0;	//定义初始化常量a
    int* p;	//定义指针p
    p=&a;	//指针p指向a的地址,即指针获取地址


    (2)、数组指针的定义


    int a[]={0,1,2,3,4,5,6,7,8,9};	//定义数组
    int* p=a;	//定义并赋值数组指针,即获得数组的首地址


    (3)、函数指针的定义


    int f();	//定义函数
    int (*p)();	//定义函数指针
    p=f;	//赋值函数指针,即获得函数代码的首地址
    
    
    


    区别变量指针、数组指针和函数指针的定义的示例代码如下。


    #include<iostream>
    using namespace std;
    
    int f()	//定义一个函数
    {
    	cout<<"测试函数指针的使用"<<endl<<endl;
    	return 0;
    }
    
    void main()
    {
    	cout<<"==========变量指针的使用=========="<<endl;
    	int a=5;
    	int* p=0;	//初始化指针为0
    	int* q;		//定义指针
    	q=&a;		//赋值指针
    	cout<<"a = "<<a<<endl;		//变量a的值
    	cout<<"a = "<<*q<<endl;		//变量a的值
    	cout<<"p = "<<p<<endl;		//指针p的地址为0000 0000
    	cout<<"&a = "<<&a<<endl;	//获取a的地址
    	cout<<"&a = "<<q<<endl;		//获取a的地址
    
    	cout<<"==========数组指针的使用=========="<<endl;
    	int b[]={0,1,2,3,4,5,6,7,8,9};
    	int* pb=b;		//直接指向第一个元素的地址
    	cout<<pb<<endl	//第1个元素的地址,即数组的首地址
    		<<b<<endl	//第1个元素的地址,即数组的首地址
    		<<*pb<<endl	//第1个元素的值
    		<<(*pb+2)<<endl;	//第3个元素的值
    
    	cout<<"==========函数指针的使用=========="<<endl;
    	int f();		//定义函数
    	int (*pf)();	//定义函数指针
    	pf=f;			//赋值函数指针,即将函数的首地址赋值给指针pf
    	(*pf)();		//通过函数指针调用函数
    }
    

    结果如下图:



    3、数组指针与指针数组


    数组指针是一个指针变量,它指向一个数组,即指向一个数组的指针就是数组指针;而指针数组是一个只包含指针元素的数组,它的元素可以指向相同类型的不同对象。


    4、函数指针与指针函数


    函数指针就是指向函数的存储空间地址的指针,可以对函数指针进行赋值并且通过函数指针来调用函数,它的本质是一个指针。而指针函数只是说明它是一个返回值为指针的函数,其本质是一个函数。


    5、引用传递、值传递和指针传递


    C++语言中,函数的参数和返回值的传递方式有3种:即值传递、引用传递和指针传递。


    (1)、值传递


    形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,不能传出。当函数内部需要修改参数,并且不希望这个改变影响调用者时,采用值传递。



    (2)、指针传递


    形参为指向实参地址的指针,当对形参的指向操作时,就相当于对实参本身进行的操作。



    (3)、引用传递


    形参相当于是实参的“别名”,对形参的操作其实就是对实参的操作,在引用传递过程中,被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。


    最后,总结一下指针和引用的相同点和不同点:


    相同点:


    都是地址的概念,指针指向一块内存,它的内容是所指内存的地址;而引用则是某块内存的别名。


    不同点:


    指针是一个实体,而引用仅是个别名;


    引用只能在定义时被初始化一次,之后不可变;指针可变;引用“从一而终”,指针可以“见异思迁”;


    引用没有const,指针有const,const的指针不可变;(具体指没有int& const a这种形式,而const int& a是有的,前者指引用本身即别名不可以改变,这是当然的,所以不需要这种形式,后者指引用所指的值不可以改变)


    引用不能为空,指针可以为空;


    “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身的大小;


    指针和引用的自增(++)运算意义不一样;


    引用是类型安全的,而指针不是(引用比指针多了类型检查)。



    展开全文
  • c语言函数指针_指针函数_返回值是函数指针

    千次阅读 多人点赞 2019-03-06 17:38:43
    其中,后缀运算符括号“()”表示这是一个函数,其前缀运算符星号“*”表示此函数指针函数,其函数值为指针,即它带回来的值的类型为指针,当调用这个函数后,将得到一个“指向返回值为…的指针(地址),“类型...

    用函数指针作为函数的返回值

    1.指针函数的定义

    顾名思义,指针函数即返回指针的函数。其一般定义形式如下:

    类型名 *函数名(函数参数表列);

    其中,后缀运算符括号“()”表示这是一个函数,其前缀运算符星号“*”表示此函数为指针型函数,其函数值为指针,即它带回来的值的类型为指针,当调用这个函数后,将得到一个“指向返回值为…的指针(地址),“类型名”表示函数返回的指针指向的类型”。

    “(函数参数表列)”中的括号为函数调用运算符,在调用语句中,即使函数不带参数,其参数表的一对括号也不能省略。其示例如下:

    int *pfun(int, int);

    由于“*”的优先级低于“()”的优先级,因而pfun首先和后面的“()”结合,也就意味着,pfun是一个函数。即:

    int *(pfun(int, int));

    接着再和前面的“*”结合,说明这个函数的返回值是一个指针。由于前面还有一个int,也就是说,pfun是一个返回值为整型指针的函数。

    我们不妨来再看一看,指针函数与函数指针有什么区别?

    int (*pfun)(int, int);

    通过括号强行将pfun首先与“*”结合,也就意味着,pfun是一个指针,接着与后面的“()”结合,说明该指针指向的是一个函数,然后再与前面的int结合,也就是说,该函数的返回值是int。由此可见,pfun是一个指向返回值为int的函数的指针。

    虽然它们只有一个括号的差别,但是表示的意义却截然不同。函数指针的本身是一个指针,指针指向的是一个函数。指针函数的本身是一个函数,其函数的返回值是一个指针。

    2. 用函数指针作为函数的返回值

    在上面提到的指针函数里面,有这样一类函数,它们也返回指针型数据(地址),但是这个指针不是指向intchar之类的基本类型,而是指向函数。对于初学者,别说写出这样的函数声明,就是看到这样的写法也是一头雾水。比如,下面的语句:

    int (*ff(int))(int *, int);

    我们用上面介绍的方法分析一下,ff首先与后面的()结合,即:

    int (*(ff(int)))(int *, int); // 用括号将ff(int)再括起来

    也就意味着ff是一个函数。

    接着与前面的*结合,说明ff函数的返回值是一个指针。然后再与后面的()结合,也就是说,该指针指向的是一个函数。

    这种写法确实让人非常难懂,以至于一些初学者产生误解,认为写出别人看不懂的代码才能显示自己水平高。而事实上恰好相反,能否写出通俗易懂的代码是衡量程序员是否优秀的标准。一般来说,用typedef关键字会使该声明更简单易懂。在前面我们已经见过:

    int (*PF)(int *, int);

    也就是说,PF是一个函数指针“变量”。当使用typedef声明后,则PF就成为了一个函数指针“类型”,即:

    typedef int (*PF)(int *, int);

    这样就定义了返回值的类型。然后,再用PF作为返回值来声明函数:

    PF ff(int);

    下面将以程序清单1为例,说明用函数指针作为函数的返回值的用法。当程序接收用户输入时,如果用户输入d,则求数组的最大值,如果输入x,则求数组的最小值,如果输入p,则求数组的平均值。

     

     

    1.函数指针的定义


      顾名思义,函数指针就是函数的指针。它是一个指针,指向一个函数。看例子:

    ?

    1

    2

    3

    A) char * (*fun1)(char * p1,char * p2);

    B) char * *fun2(char * p1,char * p2);

    C) char * fun3(char * p1,char * p2);

      

    看看上面三个表达式分别是什么意思?


    C)这很容易,fun3是函数名,p1,p2是参数,其类型为char *型,函数的返回值为char *类型。
    B) 也很简单,与C)表达式相比,唯一不同的就是函数的返回值类型为char**,是个二级指针。
    A) fun1是函数名吗?回忆一下前面讲解数组指针时的情形。我们说数组指针这么定义或许更清晰:

    ?

    1

    int (*)[10] p;

    再看看A)表达式与这里何其相似!明白了吧。这里fun1不是什么函数名,而是一个指针变量,它指向一个函数。这个函数有两个指针类型的参数,函数的返回值也是一个指针。同样,我们把这个表达式改写一下:

    ?

    1

    char * (*)(char * p1,char * p2) fun1;

    这样子是不是好看一些呢?只可惜编译器不这么想。^_^。

     

    2.函数指针使用的例子


      上面我们定义了一个函数指针,但如何来使用它呢?先看如下例子:

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    #include <stdio.h>

    #include <string.h>

    char * fun(char * p1,char * p2)

    {

      int i = 0;

      i = strcmp(p1,p2);

      if (0 == i)

      {

        return p1;

      }

      else

      {

        return p2;

      }

    }

    int main()

    {

      char * (*pf)(char * p1,char * p2);

      pf = &fun;

      (*pf) ("aa","bb");

      return 0;

    }

      我们使用指针的时候,需要通过钥匙(“*”)来取其指向的内存里面的值,函数指针使用也如此。通过用(*pf)取出存在这个地址上的函数,然后调用它。

      这里需要注意到是,在Visual C++6.0里,给函数指针赋值时,可以用&fun或直接用函数名fun。这是因为函数名被编译之后其实就是一个地址,所以这里两种用法没有本质的差别。这个例子很简单,就不再详细讨论了。

     

    3.*(int*)&p ----这是什么?


      也许上面的例子过于简单,我们看看下面的例子:

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    void Function()

    {

      printf("Call Function!\n");

    }<br>

    int main()

    {

      void (*p)();

      *(int*)&p=(int)Function;

      (*p)();

      return 0;

    } 


    这是在干什么?*(int*)&p=(int)Function;表示什么意思?
    别急,先看这行代码:

    ?

    1

    void (*p)();

    这行代码定义了一个指针变量p,p指向一个函数,这个函数的参数和返回值都是void。
    &p是求指针变量p本身的地址,这是一个32位的二进制常数(32位系统)。
    (int*)&p表示将地址强制转换成指向int类型数据的指针
    (int)Function表示将函数的入口地址强制转换成int类型的数据。
    分析到这里,相信你已经明白*(int*)&p=(int)Function;表示将函数的入口地址赋值给指针变量p。


    那么(*p) ();就是表示对函数的调用。


    讲解到这里,相信你已经明白了。其实函数指针与普通指针没什么差别,只是指向的内容不同而已。
    使用函数指针的好处在于,可以将实现同一功能的多个模块统一起来标识,这样一来更容易后期的维护,系统结构更加清晰。或者归纳为:便于分层设计、利于系统抽象、降低耦合度以及使接口与实现分开。

     

     

    4.(*(void(*) ())0)()------这是什么?


      是不是感觉上面的例子太简单,不够刺激?好,那就来点刺激的,看下面这个例子:

    ?

    1

    (*(void(*) ())0)();

    这是《C Traps and Pitfalls》这本经典的书中的一个例子。没有发狂吧?下面我们就来分析分析:

    ?

    1

    2

    3

    4

    第一步:void(*) (),可以明白这是一个函数指针类型。这个函数没有参数,没有返回值。

    第二步:(void(*) ())0,这是将0强制转换为函数指针类型,0是一个地址,也就是说一个函数存在首地址为0的一段区域内。

    第三步:(*(void(*) ())0),这是取0地址开始的一段内存里面的内容,其内容就是保存在首地址为0的一段区域内的函数。

    第四步:(*(void(*) ())0)(),这是函数调用。


    好像还是很简单是吧,上面的例子再改写改写:

    ?

    1

    (*(char**(*) (char **,char **))0) ( char **,char **);


    如果没有上面的分析,肯怕不容易把这个表达式看明白吧。不过现在应该是很简单的一件事了。读者以为呢?

     

    5.函数指针数组

     

      现在我们清楚表达式

    ?

    1

    char * (*pf)(char * p);

    定义的是一个函数指针pf。既然pf是一个指针,那就可以储存在一个数组里。把上式修改一下:

    ?

    1

    char * (*pf[3])(char * p);

    这是定义一个函数指针数组

     

      它是一个数组,数组名为pf,数组内存储了3个指向函数的指针。这些指针指向一些返回值类型为指向字符的指针、参数为一个指向字符的指针的函数。

      这念起来似乎有点拗口。不过不要紧,关键是你明白这是一个指针数组,是数组。函数指针数组怎么使用呢?这里也给出一个非常简单的例子,只要真正掌握了使用方法,再复杂的问题都可以应对。

     

    如下:

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    #include <stdio.h>

    #include <string.h>

    <br>char * fun1(char * p)

    {

      printf("%s\n",p);

      return p;

    }

    char * fun2(char * p)

    {

      printf("%s\n",p);

      return p;

    }

    char * fun3(char * p)

    {

      printf("%s\n",p);

      return p;

    }

    <br>int main()

    {

      char * (*pf[3])(char * p);

      pf[0] = fun1; //可以直接用函数名

      pf[1] = &fun2; //可以用函数名加上取地址符

      pf[2] = &fun3;<br>

      pf[0]("fun1");

      pf[0]("fun2");

      pf[0]("fun3");

      return 0;

    } 

     

    6.函数指针数组的指针


      看着这个标题没发狂吧?函数指针就够一般初学者折腾了,函数指针数组就更加麻烦,现在的函数指针数组指针就更难理解了。
    其实,没这么复杂。前面详细讨论过数组指针的问题,这里的函数指针数组指针不就是一个指针嘛。只不过这个指针指向一个数组,这个数组里面存的都是指向函数的指针。仅此而已。


    下面就定义一个简单的函数指针数组指针:

    ?

    1

    char * (*(*pf)[3])(char * p);


    注意,这里的pf和上一节的pf就完全是两码事了。上一节的pf并非指针,而是一个数组名;这里的pf确实是实实在在的指针。这个指针指向一个包含了3个元素的数组;这个数字里面存的是指向函数的指针;这些指针指向一些返回值类型为指向字符的指针、参数为一个指向字符的指针的函数。

      这比上一节的函数指针数组更拗口。其实你不用管这么多,明白这是一个指针就ok了。其用法与前面讲的数组指针没有差别。下面列一个简单的例子:

    ?

    1

    2

    3

    4

    5

    6

    7

    8

    9

    10

    11

    12

    13

    14

    15

    16

    17

    18

    19

    20

    21

    22

    23

    24

    25

    26

    27

    28

    29

    30

    31

    32

    33

    34

    35

    36

    #include <stdio.h>

    #include <string.h>

    char * fun1(char * p)

    {

    printf("%s\n",p);

    return p;

    }

    char * fun2(char * p)

    {

    printf("%s\n",p);

    return p;

    }

    char * fun3(char * p)

    {

    printf("%s\n",p);

    return p;

    }

    int main()

    {

    char * (*a[3])(char * p);

    char * (*(*pf)[3])(char * p);

    pf = &a;

    a[0] = fun1;

    a[1] = &fun2;

    a[2] = &fun3;

    pf[0][0]("fun1");

    pf[0][1]("fun2");

    pf[0][2]("fun3");

    return 0;

    }

    展开全文
  • C语言,指针函数函数指针的区别

    千次阅读 2018-04-14 15:00:25
    因此“函数指针本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个入口地址,该入口地址就是函数...
  • 函数指针指针函数

    千次阅读 2009-09-06 23:01:00
     因而“函数指针本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个入口地址,该入口地址就是函数...
  • 指针函数函数指针有什么区别 1,这两个概念都是简称,指针函数是指带指针函数,即本质是一个函数。我们知道函数都又返回类型(如果不返回值,则为无值型),只不过指针函数返回类型是某一类型的指针。其定义格式...
  • 1. 问题:在C语言中,当调用子函数并传入指针参数,在子函数中想修改指针本身的时候却发现不对劲,查阅资料后才发现原来是自己理解错了。 2. 代码:void fun( int *a ) { int b = 10; a = &b; }int main() { int ...
  • 函数指针 VS 指针函数

    千次阅读 2007-07-29 08:03:00
     函数指针函数指针”是指向函数指针变量,因而“函数指针本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一...
  • 一、指针函数 定义:指针函数是一种返回值为指针函数。 但是这么写很不清晰。 举例: A *createA();声明了一个返回值为指向A类型(即class A)的指针,参数列表为空的函数 #include<iostream> using namespace...
  • 指针函数函数指针的理解与应用

    千次阅读 多人点赞 2019-02-11 13:11:01
    指针函数 指针函数, 即返回值为指针函数, 本质上是一个函数, 我们先看下面实例: #include &amp;lt;stdio.h&amp;gt; #include &amp;lt;time.h&amp;gt; int year; int mon; int day; ...
  • 犯晕的函数指针指针函数

    千次阅读 2011-11-26 15:14:11
    函数指针指针函数,编程每天都看见,却每天都不当回事,直到有人问什么是指针函数函数指针,自己才知道自己犯晕了。于是赶快看资料温习温习。。。   1.指针函数是指函数的返回值类型是一个指针类型,即本质是...
  • 指针数组表达式为:int *p[5] ...其实指针数组表达就是一个存放指针的数组。 其图示如下: 数组指针表达式为:int (*p2)[5] 理解:括号运算符()的优先级是最高的,因此p2先和括号内的指针运算符*结合,
  • C在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址,这个函数入口地址就称为函数指针。 2、函数指针的作用: (1)、调用函数:调用的时候,用该指针变量代替函数名即可 (2)、将该函数...
  • 数组指针的定义 数组名的指针,即数组首元素地址的指针。即是指向数组的指针。 例:int (*p)[10]; p即为指向数组的指针,又称数组指针。 数组指针指针数组 数组指针是指向数组首元素的地址的指针,其本质为...
  • iOS基础知识:指针函数函数指针

    千次阅读 2015-11-18 21:47:34
     其实就是指针函数,本质上还是一个函数  当函数的返回值,是一个指针的时候,就叫指针函数。  定义语法:  类型 * 函数名(参数列表){  函数体;  }  注意:这个*可以放在类型和函数名中间的任意位置  ...
  • 通过线程来谈指针函数函数指针

    千次阅读 2012-08-21 10:57:22
    线程中遇到pthread_create函数第三个参数 void *(*start_routine)(void *) 这个参数代表一个指针,这个指针指向的函数必须满足以下条件: 1、函数参数只有一个为void...函数指针:指向函数名的指针函数指针。 e
  • C语言函数内部改变指针本身

    千次阅读 2011-06-14 17:06:00
    今天发一个C语言基础的小知识点:C语言中函数参数传递方式只有一种:值传递。   可能大家在刚开始学习C的时候都被一些教材误导,认为C中有值传递和地址传递两种方式。其实只有值传递一种,无论函数以什么形式进行...
  • 函数指针

    千次阅读 2014-11-02 15:23:32
    定义 函数指针是指指向函数而非指向对象的指针。像其他指针一样,函数指针也指向某个特定的类型(特定的函数类型)。函数类型由其返回类型以及形参表确定,而与函数名无关。如下声明了一个函数指针: bool (*pFunc)...
  • C++函数指针详解

    2021-01-21 17:09:41
    函数指针所指向的类型,是函数本身。我们知道,指针所指向类型代表了指针所指向的内存区域的大小。所以函数指针所指向的类型,是函数在内存中所占据内存的大小。知道了函数的起始地址和大小,所以函数指针可以很轻易...
  • 回调函数函数指针的应用)

    千次阅读 2016-05-03 19:41:15
    # 本篇博客主要阐述回调函数函数指针的概念,并且使用回调函数实现冒泡排序,可以 实现不同数据类型的排序。...回调函数就是一个通过函数指针调用的函数。如果你把函数指针(地址)作为参数传递给另 一个函数
  • 指针函数 函数指针

    千次阅读 2007-10-31 23:23:00
    指针函数 函数指针2007-05-16 11:04 一、指针函数 当一个函数声明其返回值为一个指针时,实际上就是返回一个地址给调用函数,以用于需要指针或地址的表达式中。 格式: 类型说明符 * 函数名(参数) 当然了,由
  • 详解函数指针和类成员函数指针

    千次阅读 2017-11-12 21:35:56
    函数指针,顾名思义即指向函数指针。 如果要问,为什么能用一个指针指向一个函数呢?我觉得要理解这个问题,以及要理解后面的函数指针和类成员函数指针,没有什么比从计算机原理的角度来理解更容易了。这里就简要...
  • 函数指针的使用先看如下例子:#include #include char * fun(char * p1,char * p2){int i = 0;i = strcmp(p1,p2);if (0 == i){return p1;}else{return p2;}}intmain(){char * (*pf)(char * p1,char * p2);pf = &fun;...
  • 但是总是要慢慢明白的,所以就根据网络上看到的和书上读到的,在此尽我所能得总结下,以便后续学习回过头来回忆...  书上说,在C语言中,函数本身不是变量,但可以定义指向函数的指针。这种类型的指针可以被...
  • C语言中函数指针和回调函数的详解

    万次阅读 多人点赞 2019-05-18 23:10:01
    因此“函数指针本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。如前所述,C在编译时,每一个函数都有一个入口地址,该入口地址就是函数...
  • 本文首先给出 指针相关概念 的预备知识, 即,指针的四个概念 与 相关符号 表示。而后,给出 各个 指针的 相关声明方式 。最后 ,本文给出 4 个 指针 相关概念的联合实例 与 输出。
  • C++函数指针

    千次阅读 2019-03-03 16:05:26
    函数指针 函数指针指向的是函数并不是对象。和其他指针一样,函数指针指向某种特定类型,函数的类型由它的返回类型和形参类型共同决定,与函数名无关。...//pf就是指向函数指针,该函数的形参为const...
  • C/C++ 函数指针

    千次阅读 多人点赞 2018-06-02 17:01:19
    因此“函数指针本身首先应是指针变量,只不过该指针变量指向函数。扩展:函数指针指针函数的区别? 他们只是名字比较像。函数指针是指向函数指针变量,本质是一个指针。而指针函数是返回值为指针的一个函数...
  • 函数名/函数地址/函数指针

    千次阅读 2017-02-13 15:45:28
    函数指针:1。指针变量 2。指针变量指向函数 ...这正如用指针变量可指向整型变量、字符型、数组一样。...在编译时,每一个函数都有一个入口地址,该入口地址就是函数指针所指向的地址。 可

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 336,402
精华内容 134,560
关键字:

函数本身就是指针