指针函数与函数指针

参考:
参考1
·指针函数:返回值为指针或者地址的函数
格式:类型说明符 * 函数名(参数…)

·函数指针:指向函数的指针,该指针指向函数的地址
格式:类型说明符 (*函数名或指针的变量名)(参数)

需要注意:声明时,括号不能丢,否则意义就不一样了;如下:

char* GetChar(char* c);   // 指针函数
char (*GetChar)(cjar* c); // 函数指针

实例:摘自(参考)

//例2 函数指针示例
#include <iostream>
using namespace std;
//函数声明
double triangle_area(double &x,double &y);//三角形面积
double rectangle_area(double &x,double &y);//矩形面积
double swap_value(double &x,double &y);//交换值
double set_value(double &x,double &y);//设定长宽(高)
// double print_area(double &x,double &y);//输出面积
double print_area(double(*p)(double&,double&), double &x,double &y);//利用函数指针输出面积
//函数定义
double triangle_area(double &x,double &y)
{
    cout<<"三角形的面积为:\t"<<x*y*0.5<<endl;
    return 0.0;
}

double rectangle_area(double &x,double &y)
{
    cout<<"矩形的面积为:\t"<<x*y<<endl;
    return 0.0;
}

double swap_value(double &x,double &y)
{
    double temp;
    temp=x;
    x=y;
    y=temp;
    return 0.0;
}

double print_area(double(*p)(double &x,double &y), double &x,double &y)
{
    cout<<"执行函数前:\n";
    cout<<"x="<<x<<"  y="<<y<<endl;
    //it is coming!...
    p(x,y);
    cout<<"函数指针传值后:\n";
    cout<<"x="<<x<<"  y="<<y<<endl;
    return 0.0;
}

double set_value(double &x,double &y)
//注意参数一定要定义成引用,要不是传不出去哈!
{
    cout<<"自定义长宽(高)为:\n";
    cout<<"长为:";
    cin>>x;
    cout<<"宽或者高为:";
    cin>>y;
    return 0.0;
}

int main()
{
    bool quit=false;//初始化退出的值为否
    double a=2,b=3;//初始化两个参数a和b
    char choice;
    //声明的p为一个函数指针,它所指向的函数带有梁个double类型的参数并且返回double
    double (*p)(double &,double &);
    while(quit==false)
    {
        cout<<"退出(q); 设定长、宽或高(1); 三角形面积(2); 矩形面积(3); 交换长宽或高(4)."<<endl;
        cin>>choice;
        switch(choice)
        {
        case 'q':
            quit=true;
            break;
        case '1':
            p=set_value;
            print_area(p,a,b);
            break;
        case '2':
            p=triangle_area;
            print_area(p,a,b);         
            break;
        case  '3':
            p=rectangle_area;
            print_area(p,a,b);
            break;
        case '4':
            p=swap_value;
            print_area(p,a,b);
            break;
        default:
            cout<<"请按规矩出牌!"<<endl;
        }
    }
    return 0;
}

声明函数指针时,其返回值,参数个数,参数类型应该与需要它指向的函数保持一致;否则,编译器会报错,无法从“”转换到“”;
利用函数指针只想某个函数的时候,我们只用,也只能给出该函数的函数名,不能把参数一并给出了。比如说在上例中,如果我们把程序的第84行改成:
p=swap_value(a,b);
 那么编译器会报错:
func_pointer.cpp(84) : error C2440: “=”: 无法从“double”转换为“double (__cdecl *)(double &,double &)
这个错误的原因就是因为我们忘记了在文章一开头所讲的函数指针的一句话:函数名也是指向函数第一条指令的常量指针。因为函数指针就是指向其函数的地址的,那么我们就应该利用函数指针来指向函数名就可以了。

如果你认为上面所诉的函数指针的声明格式有点罗嗦,那么我们也可以利用typedef来简化声明和定义的操作。比如说在上例2的第61行,那么长一串。我们完全可以在在程序一开始利用typedef来代替:

typedef double (*vp)(double &,double &);
  这样一来,我们就可以把程序的第61行简化成:

vp p;
  而且,我们在声明和定义print_area()函数的时候,就可以程序的第10行和第33行换成:

//函数声明
double print_area(vp,double &x,double &y);
//函数定义
double print_area(vp p, double &x,double &y)

高级:
在看例子之前,需要强调,函数指针本质上是一个指针(从指针二字在后也可以看出),它指向的是一个函数。而指针函数是一个函数(从函数二字在后也可以看出),函数的返回值是一个指针。
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型指针。

///一个很好的指针数组与数组指针的例子
//注意指针数组和数组指针分别是如何指向二维数组的

main()
{
    static int m[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
    int (*p)[4];// 数组指针  p是指针,指向一维数组,每个一维数组有4int元素
    int i,j;
    int *q[3];// 指针数组 q是数组,数组元素是指针,3int指针
    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");

}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值