指针函数与函数指针的区别(转)

原文:http://www.cnblogs.com/gmh915/archive/2010/06/11/1756067.htmlhtml

 

函数指针的优点:在大中型程序编程中方便修改调用函数,若一个程序中调用了某一个函数5次,若后期对此修改:要将被调用函数改成另外一个新编写的函数,则要找到5个地方分别修改,可是使用函数指针的话只须要修改1次便可。程序员

 

1、编程

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

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

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

  int *f(x,y);spa

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

表示:code

float *fun();htm

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];
}

程序应该是很好理解的,子函数返回的是数组某元素的地址。输出的是这个地址里的值。

 

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

 int (*f) (int x); /* 声明一个函数指针,int表示函数返回值,f赋值为函数名,(int x)表示传入函数的参数*/

 f=func;      /* 将func函数的首地址赋给指针f */

 

指向函数的指针包含了函数的地址,能够经过它来调用函数。声明格式以下:
        类型说明符 (*函数名)(参数)
    其实这里不能称为函数名,应该叫作指针的变量名。这个特殊的指针指向一个返回整型值的函数。指针的声明必须和它指向函数的声明保持一致。

     指针名和指针运算符外面的括号改变了默认的运算符优先级。若是没有圆括号,就变成了一个返回整型指针的函数的原型声明。
    例如:
        void (*fptr)();
    
函数的地址赋值给函数指针,能够采用下面两种形式
        fptr=&Function;
        fptr=Function;(更倾向于使用这种)
    
取地址运算符&不是必需的,由于单单一个函数标识符就标号表示了它的地址,若是是函数调用,还必须包含一个圆括号括起来的参数表。
    能够采用以下两种方式来经过指针调用函数:
        x=(*fptr)();(尽可能使用这种方式,不易弄混)
        x=fptr();
    
第二种格式看上去和函数调用无异。可是有些程序员倾向于使用第一种格式,由于它明确指出是经过指针而非函数名来调用函数的。下面举一个例子:

 

/*
函数指针 <RetType> (*<fptr>) (参数表)
函数地址赋值给函数指针的两种方式:fptr=&<FuncName>;
                                  fptr=<FuncName>; 更倾向于使用这种,可是碰到上面情形不要困惑(不要觉得是二重指针什么的)
传参时数据退化为指针后,没法再使用角标的形式进行访问,同时也不能再使用sizeof()获取指向空间的大小。

 */
#include <stdio.h>
#include <stdlib.h>

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

typedef struct _caculate
{
    char caculateType;
    double result;
}CalRst;
CalRst (*funcPtr)(int, char const **);
CalRst caculator(int argc, char const *pargv[]);

int main(int argc, char const *argv[])
{
    funcp=FileFunc;
    (*funcp)();
    funcp=EditFunc;
    (*funcp)();
    funcp=&FileFunc;
    (*funcp)();

    CalRst ret;
    funcPtr=caculator;
    ret=(*funcPtr)(argc,argv);
    printf("caculateType:%c\nresult:%lf\n", ret.caculateType, ret.result);

    return 0;
}

CalRst caculator(int argc, char const*pargv[]){
    CalRst rst;
    if ( argc!=4 ){
        printf("Usage: num +|-|*|/ num\n");
        exit(-1);
    }
    double num1=atof(*(pargv+1));
    double num2=atof(*(pargv+3));

    rst.caculateType=**(pargv+2);
    switch(rst.caculateType){
    case '+':
        rst.result=num1+num2;
        break;
    case '-':
        rst.result=num1-num2;
        break;
    case '*':
        rst.result=num1*num2;
        break;
    case '/':
        rst.result=num1/num2;
        break;
    default:
        printf("error caculateType!\n");
    }

    return rst;
}

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

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

 

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

 

2、指针的指针
    指针的指针看上去有些使人费解。它们的声明有两个星号。例如:
        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上。

3、指向指针数组的指针
    指针的指针另外一用法是处理指针数组。有些程序员喜欢用指针数组来代替多维数组,一个常见的用法就是处理字符串。
        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)。采用空指针做为终止符,在树种增删元素时,就没必要改动遍历数组的代码,由于此时数组仍然以空指针做为结束。

相关文章
相关标签/搜索