加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

指针函数与函数指针的区别

(2013-04-10 09:07:15)
标签:

杂谈

分类: c++

 

 

 


  ///////基础篇//////////////

一、

在学习arm过程中发现这“指针函数”与“函数指针”容易搞错,所以今天,我自己想一次把它搞清楚,找了一些资料,首先它们之间的定义:

1、指针函数是指带指针的函数,即本质是一个函数。函数返回类型是某一类型的指针

     类型标识符    *函数名(参数表)

      int *f(x,y);

 

首先它是一个函数,只不过这个函数的返回值是一个地址值。函数返回值必须用同类型的指针变量来接受,也就是说,指针函数一定有函数返回值,而且,在主调函数中,函数返回值必须赋给同类型的指针变量。

表示:

float *fun();

float *p;

p = fun(a);

注意指针函数与函数指针表示方法的不同,千万不要混淆。最简单的辨别方式就是看函数名前面的指针*号有没有被括号()包含,如果被包含就是函数指针,反之则是指针函数。

来讲详细一些吧!请看下面

 指针函数:
    当一个函数声明其返回值为一个指针时,实际上就是返回一个地址给调用函数,以用于需要指针或地址的表达式中。
    格式:
         类型说明符 * 函数名(参数)
    当然了,由于返回的是一个地址,所以类型说明符一般都是int。
    例如:int *GetDate();
          int * aaa(int,int);
    函数返回的是一个地址值,经常使用在返回数组的某一元素地址上。

        int * GetDate(int wk,int dy);

        main()
        {
            int wk,dy;
            do
            {
                printf(Enter week(1-5)day(1-7)\n);
                scanf(%d%d,&wk,&dy);
            }
            while(wk<1||wk>5||dy<1||dy>7);
            printf(%d\n,*GetDate(wk,dy));
        }

        int * GetDate(int wk,int dy)
        {
            static int calendar[5][7]=
            {
               {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,-1}
            };
            return &calendar[wk-1][dy-1];
        }
        程序应该是很好理解的,子函数返回的是数组某元素的地址。输出的是这个地址里的值。

 

 

 

2、函数指针是指向函数的指针变量,即本质是一个指针变量。

 int (*f) (int x);

 f=func;

 

指向函数的指针包含了函数的地址,可以通过它来调用函数。声明格式如下:
        类型说明符 (*函数名)(参数)
    其实这里不能称为函数名,应该叫做指针的变量名。这个特殊的指针指向一个返回整型值的函数。指针的声明笔削和它指向函数的声明保持一致。
        指针名和指针运算符外面的括号改变了默认的运算符优先级。如果没有圆括号,就变成了一个返回整型指针的函数的原型声明。
    例如:
        void (*fptr)();
    把函数的地址赋值给函数指针,可以采用下面两种形式:
        fptr=&Function;
        fptr=Function;
    取地址运算符&不是必需的,因为单单一个函数标识符就标号表示了它的地址,如果是函数调用,还必须包含一个圆括号括起来的参数表。
    可以采用如下两种方式来通过指针调用函数:
        x=(*fptr)();
        x=fptr();
    第二种格式看上去和函数调用无异。但是有些程序员倾向于使用第一种格式,因为它明确指出是通过指针而非函数名来调用函数的。下面举一个例子:

        void (*funcp)();
        void FileFunc(),EditFunc();

        main()
        {
            funcp=FileFunc;
            (*funcp)();
            funcp=EditFunc;
            (*funcp)();
        }

        void FileFunc()
        {
            printf(FileFunc\n);
        }

        void EditFunc()
        {
            printf(EditFunc\n);
        }

        程序输出为:
            FileFunc
            EditFunc

 

主要的区别是一个是指针变量,一个是函数。在使用是必要要搞清楚才能正确使用

 

二、指针的指针
    指针的指针看上去有些令人费解。它们的声明有两个星号。例如:
        char ** cp;
    如果有三个星号,那就是指针的指针的指针,四个星号就是指针的指针的指针的指针,依次类推。当你熟悉了简单的例子以后,就可以应付复杂的情况了。当然,实际程序中,一般也只用到  二级指针,三个星号不常见,更别说四个星号了。
    指针的指针需要用到指针的地址。
        char c='A';
        char *p=&c;
        char **cp=&p;
    通过指针的指针,不仅可以访问它指向的指针,还可以访问它指向的指针所指向的数据。下面就是几个这样的例子:
        char *p1=*cp;
        char c1=**cp;
    你可能想知道这样的结构有什么用。利用指针的指针可以允许被调用函数修改局部指针变量和处理指针数组。

        void FindCredit(int **);

        main()
        {
            int vals[]={7,6,5,-4,3,2,1,0};
            int *fp=vals;
            FindCredit(&fp);
            printf(%d\n,*fp);
        }

        void FindCredit(int ** fpp)
        {
            while(**fpp!=0)
            if(**fpp<0) break;
            else (*fpp)++;
        }

    首先用一个数组的地址初始化指针fp,然后把该指针的地址作为实参传递给函数FindCredit()。FindCredit()函数通过表达式**fpp间接地得到数组中的数据。为遍历数组以找到一个负值,FindCredit()函数进行自增运算的对象是调用者的指向数组的指针,而不是它自己的指向调用者指针的指针。语句(*fpp)++就是对形参指针指向的指针进行自增运算的。但是因为*运算符高于++运算符,所以圆括号在这里是必须的,如果没有圆括号,那么++运算符将作用于二重指针fpp上。

三、指向指针数组的指针
    指针的指针另一用法旧处理指针数组。有些程序员喜欢用指针数组来代替多维数组,一个常见的用法就是处理字符串。

        char *Names[]=
        {
             Bill,
             Sam,
             Jim,
             Paul,
             Charles,
             0
        };

        main()
        {
            char **nm=Names;
            while(*nm!=0) printf(%s\n,*nm++);
        }

    先用字符型指针数组Names的地址来初始化指针nm。每次printf()的调用都首先传递指针nm指向的字符型指针,然后对nm进行自增运算使其指向数组的下一个元素(还是指针)。注意完成上述认为的语法为*nm++,它首先取得指针指向的内容,然后使指针自增。
    注意数组中的最后一个元素被初始化为0,while循环以次来判断是否到了数组末尾。具有零值的指针常常被用做循环数组的终止符。程序员称零值指针为空指针(NULL)。采用空指针作为终止符,在树种增删元素时,就不必改动遍历数组的代码,因为此时数组仍然以空指针作为结束。

 

摘自:http://www.cnblogs.com/gmh915/archive/2010/06/11/1756067.html

 

/////////////////////////另一篇文章/////////////

这两个名字不同当然所代表的意思也就不同。我刚开始看到这就吓到了,主要是中文太博大精深了,整这样的简称太专业了,把人都绕晕了。从英文解释或中文全称看就比较容易理解。

指针数组:array of pointers,即用于存储指针的数组,也就是数组元素都是指针

数组指针:a pointer to an array,即指向数组的指针

还要注意的是他们用法的区别,下面举例说明。

int* a[4]     指针数组     

                 表示:数组a中的元素都为int型指针    

                 元素表示:*a[i]   *(a[i])是一样的,因为[]优先级高于*

int (*a)[4]   数组指针     

                 表示:指向数组a的指针

                 元素表示:(*a)[i]  

注意:在实际应用中,对于指针数组,我们经常这样使用:

typedef int* pInt;
pInt a[4];

这跟上面指针数组定义所表达的意思是一样的,只不过采取了类型变换。

代码演示如下:

#include
  
using namespace std;
  
int main()
{
int c[4]={1,2,3,4};
int *a[4]; //指针数组
int (*b)[4]; //数组指针
b=&c;
//将数组c中元素赋给数组a
for(int i=0;i<4;i++)
{
a[i]=&c[i];
}
//输出看下结果
cout<<*a[1]<<endl; //输出2就对
cout<<(*b)[2]<<endl; //输出3就对
return 0;
}

注意:定义了数组指针,该指针指向这个数组的首地址,必须给指针指定一个地址,容易犯的错得就是,不给b地址,直接用(*b)[i]=c[i]给数组b中元素赋值,这时数组指针不知道指向哪里,调试时可能没错,但运行时肯定出现问题,使用指针时要注意这个问题。但为什么a就不用给他地址呢,a的元素是指针,实际上for循环内已经给数组a中元素指定地址了。但若在for循环内写*a[i]=c[i],这同样会出问题总之一句话,定义了指针一定要知道指针指向哪里,不然要悲剧。

类似的还有指针函数和函数指针,遇到了再说吧。


///////////////////////////////////进阶篇/////////////

最近在看函数指针和函数指针,觉得很容将这两者混淆,而且对一些复杂的函数指针分析起来很困难。这里我对一些例子进行了分析,希望有助于理解函数指针和指针函数,并且掌握分析函数指针和指针函数的方法。

在看例子之前,需要强调,函数指针本质上是一个指针(从指针二字在后也可以看出),它指向的是一个函数。而指针函数是一个函数(从函数二字在后也可以看出),函数的返回值是一个指针。

1. int  abc(int a)

2. int  abc[3]

3. int  **abc(int a)

4. int  (*abc)(int a)

5. int  (*abc)[6]

6. int  *abc(int a)

7. int  **(*abc[6])(int a)

8. int  **abc[6]

9. int  *(*abc)[6]

10. int  *(*abc(int a))(int a)

11. int  (*(*abc)(int a))(int a)

12. int  (**(*abc)(int a))(int a)

13. int  (*(*abc)(int a))[6]

14. int  *(*(*(*abc)(int a))[6])(int a)


解答

1. 返回值为int的函数。

2. int 型数组

3. 返回值为“int 型指针的指针”的函数。()的优先级高于*(这里指右边的*),所以abc先和()结合,即abc(int a),说明abc是一个函数(这是abc的真面目)。那么函数的返回值是什么类型的呢?abc(int a)接着和*(右边的*)结合,即*abc(int a),说明函数abc的返回值是指针类型的?那是什么类型的指针呢?从int  *(*abc(int a))可以看出,abc(int a)的返回值是指向int型指针的指针。

4. 指向函数返回值为int的函数指针。由(*abc)可以看出,*先与abc结合,所以abc是一个指针(而不是函数),该指针指向形参为int a,返回值为int的函数。

5. 指向“int 型数组”的指针。从(*abc)可以看出,abc是一个指针,那是什么类型的指针呢?(*abc)和后面的[]结合,即(*abc)[6],所以abc指向一个数组,那么数组元素的类型呢?从int (*abc)[6]可以看出,数组元素的类型为int型。再分析一遍,指针abc指向一个数组,数组的元素类型为int型,即abc是一个指向int型数组的指针。

6. 返回值为“int型指针”的函数。由于()的优先级高于*,所以abc首先和()结合,即abc(int a),由此看出abc是一个函数(而不是指针),那么该函数的返回值是什么类型的呢?abc(int a)和前面的*结合,即*abc(int a),可以看出,函数abc的返回值是指针类型的。接着,*abc(int a)和int结合,即int *abc(int a)。再分析一遍,abc是一个函数,返回值为int型指针。

7. 元素为指向“返回值为int型指针的指针的函数”的指针数组。由于[]的优先级高于*,所以abc先和[]结合,即abc[6],所以abc是一个数组。然后abc[6]和*结合,即*abc[6],说明数组abc的每个元素是指针,且该指针指向形参为int a,返回值为int指针的指针的函数。

8. int型指针的指针数组。[]的优先级高于*,所以abc首先和[]结合,即abc[],所以abc是一个数组,然后abc[6]和*(右边的*)结合,即*abc[6],可以看出数组abc的每个元素为指针。那么该指针指向什么呢?接着,*abc[6]和左边的*结合(*的结合顺序为从右到左),即*(*abc[6]),所以数组abc的每个元素为指针,且该指针指向int型的指针,也就是说,数组abc的每个元素为int型的指针的指针。

9. 指向“int型指针数组”的指针。由于()的优先级高于[],所以abc和*先结合,即*abc,所以abc是一个指针(这是本质)。而下标[]的优先级高于*,所以*abc然后和[]结合,即(*abc)[6],可以看出,abc指向的是一个数组,数组的元素类型为int *,即int型指针。

10. 返回值为“指向返回值为int型指针的函数指针”的函数。是不是有些头晕呢?没关系,不管你头晕不晕,我都会让你清醒的。由于()的优先级高于*,所以abc先和()结合,即abc(int a),说明abc是个函数,这是本质。然后abc(int a)和前面的*结合,即*abc(int a),说明函数的返回值为指针,那么该指针(ptr1)指向什么呢?int *(*abc(int a))(int a),看到红色的部分了吗?可以看出,ptr1指向一个函数,该函数形参为int a,返回值为int型指针。最后我们再分析一遍,abc(int a)函数的返回值是一个指针,该指针指向形参为int a,返回值为int型指针的函数。

11. 指向返回值为“指向返回值为int的函数指针”的函数指针。从(*abc)(int a)可以看出,abc是一个函数指针,那么该函数指针所指的函数(f)返回值是什么类型的呢?从*(*abc)(int a)可以看出,函数f的返回值为指针类型(ptr_type),那ptr_type到底是什么类型的呢(指向int,char,还是函数)?从int  (*(*abc)(int a))(int a)可以看出,ptr_type是函数指针,所指向的函数形参为(int a),返回值为int型。

12. 指向函数返回值为“返回值为int的函数指针的指针”的函数指针。分析参考11。

13. 指向函数返回值为“指向int型数组的指针”的函数指针。abc先和*结合,即*abc,abc是一个指针。接着,*abc和()结合,即(*abc)(int a),abc指向的是一个函数,即abc是一个函数指针。那么abc指向的函数返回值是什么类型呢?(*abc)(int a)接着和前面的*结合,即*(*abc)(int a),说明abc所指向的函数的返回值是一个指针,那么这个指针(ptr)指向哪儿呢?接着往下看,(*(*abc)(int a))[6],ptr指向一个数组,数组的元素类型为int型。再分析一遍,函数指针abc所指的函数返回值是一个指针,该指针指向int型的数组。

14. 指向函数返回值为“指向‘返回值为int型指针的函数指针’的数组的指针”的函数指针。看到这个表达式,你是不是头有点大了?如果你的answer是yes,那么恭喜你,说明你还是个正常的地球人。哈哈!开个玩笑。从(*abc)(int a)可以看出,abc是一个函数指针,即指针abc指向的是一个函数(f)。那么函数f的返回值是什么类型的呢?从*(*abc)(int a)可以看出,函数f的返回值类型是指针型(ptr)的,那么这个指针指向哪里呢?从(*(*abc)(int a))[6]可以看出,ptr指向一个数组,那么该数组(arr)的元素是什么类型的呢?从*(*(*abc)(int a))[6],arr的数组的元素类型为指针类型(ptr_type),那是什么类型的是指针呢(指向int,char,还是函数)?从int *(*(*(*abc)(int a))[6])(int a)可以看出,ptr_type是指向函数的指针,该函数的形参为int a,返回值为int型指针。

///////////////////////////////////一个很好的指针数组与数组指针的例子////////////
//注意指针数组和数组指针分别是如何指向二维数组的
#include
main()
{
    static int m[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
    int (*p)[4];//数组指针  p是指针,指向一维数组,每个一维数组有4个int元素
    int i,j;
    int *q[3];//指针数组 q是数组,数组元素是指针,3个int指针
    p=m;    //p是指针,可以直接指向二维数组
    printf("--数组指针输出元素--/n");
    for(i=0;i<3;i++)
    {
        for(j=0;j<4;j++)
        {
            printf("= ",*(*(p+i)+j));
        }
        printf("/n");
    }
    printf("/n");
    for(i=0;i<3;i++,p++)//p可看成是行指针
    {
        printf("= ",**p);//每一行的第一个元素
        printf("= ",*(*p+1));//每一行的第二个元素
        printf("= ",*(*p+2));//每一行的第三个元素
        printf("= ",*(*p+3));//每一行的第四个元素
        printf("/n");
    }
    printf("/n");
    printf("--指针数组输出元素--/n");
    for(i=0;i<3;i++)
        q[i]=m[i];//q是数组,元素q[i]是指针
    for(i=0;i<3;i++)
    {
        for(j=0;j<4;j++)
        {
            printf("= ",q[i][j]);//q[i][j]可换成*(q[i]+j)
        }
        printf("/n");
    }
    printf("/n");
    q[0]=m[0];
    for(i=0;i<3;i++)
    {
        for(j=0;j<4;j++)
        {
            printf("= ",*(q[0]+j+4*i));
        }
        printf("/n");
    }
    printf("/n");
   
}

///////////////////////书写格式解惑篇////////

一 通常的函数调用
    一个通常的函数调用的例子:
//自行包含头文件
  1. void MyFun(int x); //此处的申明也可写成:void MyFun( int );

  2. int main(int argc, char* argv[])
  3. {
  4.    MyFun(10); //这里是调用MyFun(10);函数

  5.       return 0;
  6. }

  7. void MyFun(int x) //这里定义一个MyFun函数
  8. {
  9.    printf(%d\n”,x);
  10. }
    这个MyFun函数是一个无返回值的函数,它并不完成什么事情。这种调用函数的格式你应该是很熟悉的吧!看主函数中调用MyFun函数的书写格式:
MyFun(10);
    我们一开始只是从功能上或者说从数学意义上理解MyFun这个函数,知道MyFun函数名代表的是一个功能(或是说一段代码)。
    直到——
    学习到函数指针概念时。我才不得不在思考:函数名到底又是什么东西呢?
    (不要以为这是没有什么意义的事噢!呵呵,继续往下看你就知道了。)

二 函数指针变量的申明
    就象某一数据变量的内存地址可以存储在相应的指针变量中一样,函数的首地址也以存储在某个函数指针变量里的。这样,我就可以通过这个函数指针变量来调用所指向的函数了。
    在C系列语言中,任何一个变量,总是要先申明,之后才能使用的。那么,函数指针变量也应该要先申明吧?那又是如何来申明呢?以上面的例子为例,我来申明一个可以指向MyFun函数的函数指针变量FunP。下面就是申明FunP变量的方法:
void (*FunP)(int) ;   //也可写成void (*FunP)(int x);
    你看,整个函数指针变量的申明格式如同函数MyFun的申明处一样,只不过——我们把MyFun改成(*FunP)而已,这样就有了一个能指向MyFun函数的指针FunP了。(当然,这个FunP指针变量也可以指向所有其它具有相同参数及返回值的函数了。)

三 通过函数指针变量调用函数
    有了FunP指针变量后,我们就可以对它赋值指向MyFun,然后通过FunP来调用MyFun函数了。看我如何通过FunP指针变量来调用MyFun函数的:
//自行包含头文件
  1. void MyFun(int x); //这个申明也可写成:void MyFun( int );
  2. void (*FunP)(int ); //也可申明成void(*FunP)(int x),但习惯上一般不这样。

  3. int main(int argc, char* argv[])
  4. {
  5.    MyFun(10); //这是直接调用MyFun函数
  6.    FunP=&MyFun; //将MyFun函数的地址赋给FunP变量
  7.    (*FunP)(20); //这是通过函数指针变量FunP来调用MyFun函数的。
  8. }

  9. void MyFun(int x) //这里定义一个MyFun函数
  10. {
  11.    printf(%d\n”,x);
  12. }
    请看黑体字部分的代码及注释。
    运行看看。嗯,不错,程序运行得很好。
    哦,我的感觉是:MyFun与FunP的类型关系类似于int 与int *的关系。函数MyFun好像是一个如int的变量(或常量),而FunP则像一个如int *一样的指针变量。
int i,*pi;
pi=&i;    //与FunP=&MyFun比较。
    (你的感觉呢?)
    呵呵,其实不然——

四 调用函数的其它书写格式
函数指针也可如下使用,来完成同样的事情:
//自行包含头文件
  1. void MyFun(int x);
  2. void (*FunP)(int ); //申明一个用以指向同样参数,返回值函数的指针变量。

  3. int main(int argc, char* argv[])
  4. {
  5.    MyFun(10); //这里是调用MyFun(10);函数
  6.    FunP=MyFun; //将MyFun函数的地址赋给FunP变量
  7.    FunP(20); //这是通过函数指针变量来调用MyFun函数的。

  8.       return 0;
  9. }

  10. void MyFun(int x) //这里定义一个MyFun函数
  11. {
  12.    printf(%d\n”,x);
  13. }
我改了黑体字部分(请自行与之前的代码比较一下)。
运行试试,啊!一样地成功。
咦?
FunP=MyFun;
可以这样将MyFun值同赋值给FunP,难道MyFun与FunP是同一数据类型(即如同的int 与int的关系),而不是如同int 与int*的关系了?(有没有一点点的糊涂了?)
看来与之前的代码有点矛盾了,是吧!所以我说嘛!
请容许我暂不给你解释,继续看以下几种情况(这些可都是可以正确运行的代码哟!):
代码之三:
  1. int main(int argc, char* argv[])
  2. {
  3.    MyFun(10); //这里是调用MyFun(10);函数
  4.    FunP=&MyFun; //将MyFun函数的地址赋给FunP变量
  5.    FunP(20); //这是通过函数指针变量来调用MyFun函数的。

  6.       return 0;
  7. }
  8. 代码之四:
  9. int main(int argc, char* argv[])
  10. {
  11.    MyFun(10); //这里是调用MyFun(10);函数
  12.    FunP=MyFun; //将MyFun函数的地址赋给FunP变量
  13.    (*FunP)(20); //这是通过函数指针变量来调用MyFun函数的。

  14.       return 0;
  15. }
真的是可以这样的噢!
(哇!真是要晕倒了!)
还有呐!看——
  1. int main(int argc, char* argv[])
  2. {
  3.    *MyFun)(10); //看,函数名MyFun也可以有这样的调用格式

  4.       return 0;
  5. }
你也许第一次见到吧:函数名调用也可以是这样写的啊!(只不过我们平常没有这样书写罢了。)
那么,这些又说明了什么呢?
呵呵!假使我是“福尔摩斯”,依据以往的知识和经验来推理本篇的“新发现”,必定会由此分析并推断出以下的结论:
1. 其实,MyFun的函数名与FunP函数指针都是一样的,即都是函数指针。MyFun函数名是一个函数指针常量,而FunP是一个函数数指针变量,这是它们的关系。
2. 但函数名调用如果都得如(*MyFun)(10);这样,那书写与读起来都是不方便和不习惯的。所以C语言的设计者们才会设计成又可允许MyFun(10);这种形式地调用(这样方便多了并与数学中的函数形式一样,不是吗?)。
3. 为统一起见,FunP函数指针变量也可以FunP(10)的形式来调用。
4. 赋值时,即可FunP=&MyFun形式,也可FunP=MyFun。
上述代码的写法,随便你爱怎么着!
请这样理解吧!这可是有助于你对函数指针的应用喽!
最后——
补充说明一点:在函数的申明处:
void MyFun(int );    //不能写成void (*MyFun)(int )。
void (*FunP)(int );   //不能写成void FunP(int )。
(请看注释)这一点是要注意的。

五 定义某一函数的指针类型:
就像自定义数据类型一样,我们也可以先定义一个函数指针类型,然后再用这个类型来申明函数指针变量。
我先给你一个自定义数据类型的例子。
  1. typedef int* PINT; //为int* 类型定义了一个PINT的别名
  2. int main()
  3. {
  4.   int x;
  5.   PINT px=&x; //与int * px=&x;是等价的。PINT类型其实就是int * 类型
  6.   *px=10; //px就是int*类型的变量
  7.   return 0;
  8. }
根据注释,应该不难看懂吧!(虽然你可能很少这样定义使用,但以后学习Win32编程时会经常见到的。)
下面我们来看一下函数指针类型的定义及使用:(请与上对照!)
//自行包含头文件
  1. void MyFun(int x); //此处的申明也可写成:void MyFun( int );
  2. typedef void (*FunType)(int ); //这样只是定义一个函数指针类型
  3. FunType FunP; //然后用FunType类型来申明全局FunP变量

  4. int main(int argc, char* argv[])
  5. {
  6. //FunType FunP; //函数指针变量当然也是可以是局部的 ,那就请在这里申明了。
  7.    MyFun(10);
  8.    FunP=&MyFun;
  9.    (*FunP)(20);

  10.       return 0;
  11. }

  12. void MyFun(int x)
  13. {
  14.    printf(%d\n”,x);
  15. }
看黑体部分:
首先,在void (*FunType)(int ); 前加了一个typedef 。这样只是定义一个名为FunType函数指针类型,而不是一个FunType变量。
然后,FunType FunP;  这句就如PINT px;一样地申明一个FunP变量。
其它相同。整个程序完成了相同的事。
这样做法的好处是:
有了FunType类型后,我们就可以同样地、很方便地用FunType类型来申明多个同类型的函数指针变量了。如下:
FunType FunP2;
FunType FunP3;
//……

六 函数指针作为某个函数的参数
既然函数指针变量是一个变量,当然也可以作为某个函数的参数来使用的。所以,你还应知道函数指针是如何作为某个函数的参数来传递使用的。
给你一个实例:
要求:我要设计一个CallMyFun函数,这个函数可以通过参数中的函数指针值不同来分别调用MyFun1、MyFun2、MyFun3这三个函数(注:这三个函数的定义格式应相同)。
实现:代码如下:
//自行包含头文件
  1. void MyFun1(int x);
  2. void MyFun2(int x);
  3. void MyFun3(int x);
  4. typedef void (*FunType)(int ); //. 定义一个函数指针类型FunType,与①函数类型一至
  5. void CallMyFun(FunType fp,int x);

  6. int main(int argc, char* argv[])
  7. {
  8.    CallMyFun(MyFun1,10); //. 通过CallMyFun函数分别调用三个不同的函数
  9.    CallMyFun(MyFun2,20);
  10.    CallMyFun(MyFun3,30);
  11. }
  12. void CallMyFun(FunType fp,int x) //. 参数fp的类型是FunType。
  13. {
  14.   fp(x);//. 通过fp的指针执行传递进来的函数,注意fp所指的函数是有一个参数的
  15. }
  16. void MyFun1(int x) //. 这是个有一个参数的函数,以下两个函数也相同
  17. {
  18.    printf(“函数MyFun1中输出:%d\n”,x);
  19. }
  20. void MyFun2(int x)
  21. {
  22.    printf(“函数MyFun2中输出:%d\n”,x);
  23. }
  24. void MyFun3(int x)
  25. {
  26.    printf(“函数MyFun3中输出:%d\n”,x);
  27. }
输出结果:略

分析:(看我写的注释。你可按我注释的①②③④⑤顺序自行分析。)
 
以上部分为转载网友所述。原文地址为:http://blog.pfan.cn/whyhappy/6030.html
 
七 地址跳转
void(*reset)(void)= (void(*)(void))0。

  void(*reset)(void)就是函数指针定义,(void(*)(void))0是强制类型转换操作,将数值“0”强制转换为函数指针地址“0”。

  通过调用reset()函数,程序就会跳转到程序执行的“0”地址处重新执行。在一些其他高级单片机Bootloader中,如NBoot、UBoot、EBoot,经常通过这些Bootloader进行下载程序,然后通过函数指针跳转到要执行程序的地址处。

  void (*theUboot)(void);
    。。。。
    theUboot = (void (*)(void))(0x30700000);
    theUboot();
    。。。。。

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

强制类型转换,将一个绝对地址转换为一个函数指针,并调用这个函数以跳转到前面提到的绝对地址.
翻译成汇编就是:
mov r0,0x30700000;
mov pc,r0

对于(*(void (*)(void))(0x30700000))();
可以这样理解

首先(void( * )(void) )是一个强制类型转换符,他将后面的0x30700000这个无符号整数强制转化为一个函数指针,该函数指针所指向的函数入口参数为 void,返回值也是void 。 如果到这步你看懂了,那么设(void (*)(void))(0x30700000)为 fp; 那么上面的表达式就可以简化为 (*fp)();   OK,这下就清楚了吧,我们将上面转化好的函数指针进行引用(也就是调用函数指针指向的函数)。

 

 

from:http://blog.chinaunix.net/space.php?uid=25524263&do=blog&id=2888273

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有