函数指针和回调函数

1 函数指针

1.1 函数类型

通过什么来区分两个不同的函数?

一个函数在编译时被分配一个入口地址,这个地址就称为函数的指针,函数名代表函数的入口地址。

这一点和数组一样,因此我们可以用一个指针变量来存放这个入口地址,然后通过该指针变量调用函数。

函数三要素: 名称、参数、返回值。C语言中的函数有自己特定的类型。

//c语言中通过typedef为函数类型重命名:
typedef int f(int, int);		// f 为函数类型
typedef void p(int);		    // p 为函数类型
注意:通过函数类型定义的变量是不能够直接执行,因为没有函数体。只能通过类型定义一个函数指针指向某一个具体函数,才能调用。

1.2 函数指针的定义方式

函数指针即指向函数的指针,它的定义方式有以下三种:

  1. 函数指针定义方式(先定义函数类型,根据类型定义指针变量);
  2. 先定义函数指针类型,根据类型定义指针变量;
  3. 直接定义函数指针变量;
#include <stdio.h>

void func(int a, char b)
{
    printf("hello world\n");
}

int main()
{
    // 1.通过typedef定义函数类型,再通过函数类型定义函数指针
    // 定义了返回值为void类型, 形参一为int类型, 形参二为char类型的函数类型pFunc1
    typedef void(pFunc1)(int, char);                                     
                                                                         
    pFunc1 *p = func;                                                    
    p(1, 'a');        // 调用方法

    // 2.通过typedef定义函数指针类型,再通过函数指针类型定义函数指针
    // 定义了返回值为void类型, 形参一为int类型, 形参二为char类型的函数指针类型pFunc2
    typedef void(*pFunc2)(int, char);

    pFunc2 p2 = func;
    p2(2, 'a');

    // 3.直接定义函数指针
    // 定义了返回值为void类型, 形参一为int类型, 形参二为char类型的函数指针pFunc3
    void(*pFunc3)(int, char) = func;
    pFunc3(3, 'a');

    return 0;
}


2 回调函数

2.1 什么是回调函数

回调函数就是一个被 作为参数 传递 的函数。 即将一个函数传递到另一个函数中去调用,被传入的函数叫做回调函数。

再说通俗一点就是:其中函数A的某一个形参为函数指针,而函数B作为函数参数传递给函数A,在函数A中调用函数B,函数B就是回调函数。

#include <stdio.h>

void A(int a, void(*pFunc)())   // 形参二为一个返回值为void类型,无形参的函数指针(函数指针做函数参数)
{
    pFunc();                    // 在函数A中调用传入的函数
}

void B() 
{
    printf("hello world\n");
}


int main()
{
    A(1, B);                    // 函数B作为函数参数传递给函数A,函数B就叫回调函数

    return 0;
}

2.2 案例

2.2.1 提供一个函数,通过传入的回调函数,实现打印任意类型的数据

#include <stdio.h>

// 形参一:数据的地址;形参二:函数指针
void myPrint(void *p, void(pFunc)(void*))
{
    pFunc(p);
}

void printInt(void *p)          // 打印int类型的回调函数
{
    int *pInt = (int*)p;
    printf("%d\n", *pInt);
}

void printDouble(void *p)       // 打印double类型的回调函数
{
    double *pDouble = (double*)p;
    printf("%f\n", *pDouble);
}

struct Person
{
    char name[64];
    int age;
};

void printPerson(void *p)       // 打印自定义数据类型Person的回调函数
{
    struct Person *pP = (struct Person*)p;
    printf("姓名:%s, 年龄:%d\n", pP->name, pP->age);
}

int main()
{
    int a = 10; 
    myPrint(&a, printInt);

    double b = 10.1;
    myPrint(&b, printDouble);

    struct Person c{"aaa", 10};
    myPrint(&c, printPerson);

    return 0;
}

2.2.2 提供一个函数,通过传入回调函数,实现对任意类型的数组进行排序(选择排序,用户可以指定排序顺序)

#include <stdio.h>

// 形参一: 数组首地址; 形参二: 数组元素个数; 形参三: 排序规则(0-升序,非0-降序); 形参四: 函数指针
void mySort(void *pArray, int arrSize, int rules, void(*pFunc)(void*, int, int))
{
    pFunc(pArray, arrSize, rules);
}

void intSort(void *p, int arrSize, int rules)   // int类型数组排序的回调函数
{
    int *pInt = (int*)p;

    for (int ii = 0; ii < arrSize; ++ii)
    {   
        int index = ii;   // 记录下标值
        for (int jj = ii+1; jj < arrSize; ++jj)
        {   
            if (rules == 0)
            {   
                if (pInt[index] > pInt[jj])
                {   
                    index = jj;   // 记录真实的最小下标值
                }   
            }   
            else
            {   
                if (pInt[index] < pInt[jj])
                {   
                    index = jj;   // 记录真实的最大的下标值
                }   
            }   
        }   

        if (ii != index)  // 判断index是否为最初的值,如果不是,说明需要交换元素
        {   
            int tmp = pInt[ii];
            pInt[ii] = pInt[index];
            pInt[index] = tmp;
        }   
    }   
}

int main()
{
    int arr[] = {5, 2, 3, 1, 0, 4}; 

    mySort(arr, sizeof(arr)/sizeof(int), 0, intSort);

    for (int ii = 0; ii < sizeof(arr)/sizeof(int); ++ii)
    {
        printf("%d\n", arr[ii]);
    }

    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值