【数据结构】C++函数指针

函数指针



前言

由(* visit)引发的搜索......

看数据结构代码,不知道这个从哪来的,搜索了一番,还是记一下比较好。

在这里插入图片描述


一、 函数指针

1.定义

所谓函数指针即定义一个指向函数的指针变量,定义的格式如下:

int (*p)(int x, int  y);  //注意:这里的括号不能掉,因为括号()的运算优先级比解引用运算符*高

这个函数的类型是有两个整型参数,返回值是个整型。对应的函数指针类型:

int (*) (int a, int b);  

对应的函数指针定义:

int (*p)(int x, int  y);  //参数名可以去掉,并且通常都是去掉的。这样指针p就可以保存函数类型为两个整型参数,返回值是整型的函数地址了。
 
int (*p)(int, int);

我们一般可以这么使用,通过函数指针调用函数:

int maxValue (int a, int b) {
    return a > b ? a : b;
}    
 
int (*p)(int, int) = NULL;  //定义一个与maxValue兼容的指针
p = maxValue;
p(20, 45);  //通过指针调用

2.用途

函数指针有两个用途:调用函数和做函数的参数。
个人感觉函数指针最大的作用就是作为函数的参数,当函数需要一个函数作为形参,而这个函数形参未定义或者不确定应该输入哪个函数时,函数指针的作用就体现出来了,使用地址传递的方式,利用函数指针作为形参可以很好地解决这个问题,这有利于程序的模块化与封装性

两个例子

1.像二叉树遍历中使用的 *visit() 函数指针,我们并不清楚,visit应该是输出、操作、赋值等等哪一个函数,因此使用 *visit函数指针,等实际输入时再确定它是哪一个函数。

template<class T>
void BinTree<T>::Preorder(BinTreeNode<T> *subtree,void (*visit)(BinTreeNode<T> *s)){
    if(subtree!=NULL){
        visit(subtree);
        Preorder(subtree->leftChild,visit);
        Preorder(subtree->rightChild,visit);
    }
 }
void printnode(BinTreeNode<char> *tnode){
     cout<<tnode->data<<' ';
}
int main(){
    BinTree<char> t;
    t.buildtree();
    t.Levelorder(printnode);
    t.Inorder(printnode);
    return 0;
}

2 借助于函数指针作为参数实现“动态排序”

首先我们应该理解动态这个词,我的理解就是不同时刻,不同场景,发生不同的事,这就是动态。动态排序就是根据不同的排序指标进行排序,不用书写很多重复性的代码,话不多说,直接上案例。

需求: 有30个学生需要排序
按成绩排
按年龄排

这种无法预测的需求变更,就是我们上文说的动态场景,那么解决方案就是函数回调:

//定义一个结构体
typedef struct student
{
    char name[20];
    int age;
    float score;
}Student;
 
//比较两个学生的年龄
BOOL compareByAge(Student stu1, Student stu2)
 {
    return stu1.age > stu2.age ? YES : NO;
}
 
//比较两个学生的成绩
BOOL compareByScore(Student stu1, Student stu2) 
{
    return stu1.score > stu2.score ? YES : NO;
}
 
void sortStudents(Student *array, int n, BOOL(*p)(Student, Student)) 
{
    Student temp;
    int flag = 0;
    for (int i = 0; i < n - 1 && flag == 0; i++) 
    {
        flag = 1;
        for (int j = 0; j < n - i - 1; j++) 
        {
            if (p(array[j], array[j + 1])) 
            {
                temp = array[j];
                array[j] = array[j + 1];
                array[j + 1] = temp;
                flag = 0;
            }
        }
    }
}
 
int main() {
 
    Student stu1 = {"小明", 19, 98};
    Student stu2 = {"小红", 20, 78};
    Student stu3 = {"小白", 21, 88};
    Student stuArray[3] = {stu1, stu2, stu3};
    sortStudents(stuArray, 3, compareByAge);//按年龄排
    sortStudents(stuArray, 3, compareByScore);//按成绩排
    return 0;
}

不难看出,这样使用的便捷性(有点像模板的作用)
--------------------一个小总结--------------------

//定义一个相同类型的函数指针
BOOL(*p)(Student, Student)
//写出两个会使用到的不同函数
BOOL compareByAge(Student stu1, Student stu2)
BOOL compareByScore(Student stu1, Student stu2) 
//在另一个函数中调用
void sortStudents(Student *array, int n, BOOL(*p)(Student, Student)) {
    ....
  if (p(array[j], array[j + 1])) 
  {
    ....
  }
    ....
}

//在主函数里确定真正调用的函数
int main() {
    ....
    sortStudents(stuArray, 3, compareByAge);//按年龄排
    sortStudents(stuArray, 3, compareByScore);//按成绩排
    ....
}

3.注意事项

我们可以将printnode函数定义为模板函数

template<class T> void printnode(BinTreeNode<T> *tnode){
     cout<<tnode->data<<' ';
}

但如果在主函数里定义visit的函数指针模板, 直接如下所示

template<class T> void (*visit)(BinTreeNode<T> *tnode);

c++会报错,(原因我也不太清楚)

解决方法: 把函数指针封装在一个模板结构或模板类里,像在BinTree类中,我们定义一个模板函数指针就可以通过

template <class T>
struct Type {
   void (*visit)(BinTreeNode<T> *tnode)};

或是放到一个模板函数内,让函数指针作为一个形参,在函数内再调用指针指向的函数,但这样也就没有特意定义它的必要,他也就像二叉树遍历函数中的用法一样,作为函数形参,不需要特别定义。

template <class T> void Func( void (*visit)(BinTreeNode<T> *tnode),BinTreeNode<T> *tnode) {
  printnode(BinTreeNode<T> *tnode);
}

二、指针函数

1.定义

指针函数:指的是函数的返回值是一个指针,比如我的函数返回的是一个指向整数int的指针,定义格式如下:

int *p(int a,int b); //注意这里的*与P之间是没有括号的,所以含义是函数p(int,int)会返回一个(int *)指针
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值