c语言函数指针和回调函数(某马)

1.函数指针

  • 1.1 函数类型

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

    • 一个函数在编译时被分配一个入口地址,这个地址就称为函数的指针,函数名代表函数的入口地址。
    • 函数三要素: 名称、参数、返回值。C语言中的函数有自己特定的类型。
  • c语言中通过typedef为函数类型重命名:

typedef int f(int, int);        // f 为函数类型
typedef void p(int);        // p 为函数类型
  • 这一点和数组一样,因此我们可以用一个指针变量来存放这个入口地址,然后通过该指针变量调用函数。

注意:通过函数类型定义的变量是不能够直接执行,因为没有函数体。只能通过类型定义一个函数指针指向某一个具体函数,才能调用。

typedef int(p)(int, int);

void my_func(int a,int b){
    printf("%d %d\n",a,b);
}

void test(){

    p p1;//p1(10,20); //错误,不能直接调用,只描述了函数类型,但是并没有定义函数体,没有函数体无法调用
    p* p2 = my_func;
    p2(10,20); //正确,指向有函数体的函数入口地址
}
  • 1.2 函数指针(指向函数的指针)

  • 函数指针定义方式(先定义函数类型,根据类型定义指针变量);
  • 先定义函数指针类型,根据类型定义指针变量;
  • 直接定义函数指针变量;
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

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

void test01()
{
    //1、先定义出函数类型,再通过类型定义函数指针
    typedef void(FUNC_TYPE)(int, char);

    FUNC_TYPE * pFunc = func;
    //pFunc(10, 'a');

    //2、定义出函数指针类型,通过类型定义函数指针变量
    typedef void( * FUNC_TYPE2)(int, char);

    FUNC_TYPE2 pFunc2 = func;
    //pFunc2(20, 'b');


    //3、直接定义函数指针变量
    void(*pFunc3)(int, char) = func;
    pFunc3(30, 'c');

    //函数指针 和 指针函数 区别?
    //函数指针  指向了函数的指针
    //指针函数  函数返回值是指针的函数
}


//函数指针的数组
void func1()
{
    printf("func1 调用了\n");
}

void func2()
{
    printf("func2 调用了\n");
}

void func3()
{
    printf("func3 调用了\n");
}

void test02()
{
    void(*pArray[3])(); 

    pArray[0] = func1;
    pArray[1] = func2;
    pArray[2] = func3;

    for (int i = 0; i < 3;i++)
    {
        pArray[i]();
    }
}

int main()
{
    //test01();
    test02();

    system("pause");
    return EXIT_SUCCESS;
}
  • 1.3 函数指针数组

函数指针数组,每个元素都是函数指针。

void func01(int a){
    printf("func01:%d\n",a);
}
void func02(int a){
    printf("func02:%d\n", a);
}
void func03(int a){
    printf("func03:%d\n", a);
}

void test(){

#if 0
    //定义函数指针
    void(*func_array[])(int) = { func01, func02, func03 };
#else
    void(*func_array[3])(int);
    func_array[0] = func01;
    func_array[1] = func02;
    func_array[2] = func03;
#endif

    for (int i = 0; i < 3; i ++){
        func_array[i](10 + i);
        (*func_array[i])(10 + i);
    }
}

2. 函数指针做函数参数(回调函数)

函数参数除了是普通变量,还可以是函数指针变量。
//形参为普通变量
void fun( int x ){}
//形参为函数指针变量
void fun( int(*p)(int a) ){}
函数指针变量常见的用途之一是把指针作为参数传递到其他函数,指向函数的指针也可以作为参数,以实现函数地址的传递。

  • 函数指针做函数参数.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//提供一个打印函数,可以打印任意类型的数据
void printText( void * data , void(*myPrint)(void *) )
{
    myPrint(data);

}



void myPrintInt(void * data)
{
    int * num = data;
    printf("%d\n", *num);
}

void test01()
{
    int a = 10;
    printText(&a, myPrintInt);
}


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

void myPrintPerson(void * data)
{
    struct Person * p = data;
    printf("姓名: %s 年龄: %d\n", p->name, p->age);
}

void test02()
{
    struct Person p = { "Tom", 18 };

    printText(&p, myPrintPerson);

}

int main(){

    //test01();
    test02();
    system("pause");
    return EXIT_SUCCESS;
}
int plus(int a, int b)
{
    return a + b;
}
int sub(int a, int b)
{
    return a - b;
}
int mul(int a, int b)
{
    return a * b;
}
int division(int a, int b)
{
    return a / b;
}

//函数指针 做函数的参数 --- 回调函数
void Calculator(int(*myCalculate)(int, int), int a, int b)
{
    int ret = myCalculate(a, b); //dowork中不确定用户选择的内容,由后期来指定运算规则
    printf("ret = %d\n", ret);
}

void test01()
{
    printf("请输入操作符\n");
    printf("1、+ \n");
    printf("2、- \n");
    printf("3、* \n");
    printf("4、/ \n");

    int select = -1;
    scanf("%d", &select);

    int num1 = 0;
    printf("请输入第一个操作数:\n");
    scanf("%d", &num1);

    int num2 = 0;
    printf("请输入第二个操作数:\n");
    scanf("%d", &num2);

    switch (select)
    {
    case  1:
        Calculator(plus, num1, num2);
        break;
    case  2:
        Calculator(sub, num1, num2);
        break;
    case 3:
        Calculator(mul, num1, num2);
        break;
    case 4:
        Calculator(division, num1, num2);
        break;
    default:
        break;
    }

}


  • 回调函数案例.c
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//提供一个函数,实现可以打印任意类型的数组 

void printAllArray(void * pArray , int eleSize, int len , void(*myPrint)(void*) )
{
    char * p = pArray;

    for (int i = 0; i < len;i++)
    {
        //获取数组中每个元素的首地址
        char * eleAddr = p + eleSize * i;
        //printf("%d\n", *(int *)eleAddr);
        //交还给用户做打印操作
        myPrint(eleAddr);
    }

}

void myPrintInt(void * data)
{
    int * num = data;
    printf("%d\n", *num);
}

void test01()
{
    int arr[5] = { 1, 2, 3, 4, 5 };
    int len = sizeof(arr) / sizeof(int);
    printAllArray(arr, sizeof(int), len, myPrintInt);
}

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

void myPrintperson(void * data)
{
    struct Person * p = data;
    printf("姓名:%s  年龄:%d \n", p->name, p->age);
}


//查找数组中的元素是否存在
//参数1  数组首地址   参数2  每个元素的大小  参数3  数组元素个数  参数4 查找数据
int findArrayEle(void * pArray, int eleSize, int len, void * data ,  int(*myCompare)(void* ,void* )  )
{
    char * p = pArray;

    for (int i = 0; i < len;i++)
    {
        //每个元素的首地址
        char * eleAddr = p + eleSize * i;

        //if ( 数组中的变量的元素 == 用户传入的元素)
        if ( myCompare(eleAddr,data)  )
        {
            return 1;
        }
    }

    return 0;

}

int myComparePerson(void * data1,void * data2)
{
    struct Person * p1 = data1;
    struct Person * p2 = data2;

    //if ( strcmp( p1->name , p2->name) == 0  &&  p1->age == p2->age)
    //{
    //  return 1;
    //}
    //return  0;

    return   strcmp(p1->name, p2->name) == 0 && p1->age == p2->age;

}

void test02()
{
    struct Person personArray[] =
    {
        { "aaa", 10 },
        { "bbb", 20 },
        { "ccc", 30 },
        { "ddd", 40 },
    };
    int len = sizeof(personArray) / sizeof(struct Person);
    printAllArray(personArray, sizeof(struct Person), len, myPrintperson);

    //查找数组中指定的元素是否存在
    struct Person p = { "ccc", 30 };

    int ret = findArrayEle(personArray, sizeof(struct Person), len, &p, myComparePerson);

    if (ret)
    {
        printf("找到了元素\n");
    }
    else
    {
        printf("未找到\n");
    }
}

int main(){

    //test01();
    test02();
    system("pause");
    return EXIT_SUCCESS;
}



注意:函数指针和指针函数的区别:

  • 函数指针是指向函数的指针;
  • 指针函数是返回类型为指针的函数;
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容