• 【C语言深入理解指针(4)】


    1.回调函数是什么?

    回调函数就是一个通过函数指针调用的函数。

    如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数时,被调⽤的函数就是回调函数。回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。

    第13讲中我们写的计算机的实现的代码中,红⾊框中的代码是重复出现的,其中虽然执⾏计算的逻辑是区别的,但是输⼊输出操作是冗余的,有没有办法,简化⼀些呢?

    因为红⾊框中的代码,只有调⽤函数的逻辑是有差异的,我们可以把调⽤的函数的地址以参数的形式传递过去,使⽤函数指针接收,函数指针指向什么函数就调⽤什么函数,这⾥其实使⽤的就是回调函数的功能。

    (1)使用回调函数改造前

    //使⽤回调函数改造前
    #include 
    int add(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 div(int a, int b)
    {
     return a / b;
    }
    int main()
    {
     int x, y;
     int input = 1;
     int ret = 0;
     do
     {
     printf("******************
     printf(" 1:add 
     printf(" 3:mul 
     printf("******************
     printf("请选择:");
     scanf("%d", &input);
     switch (input)
     {
     case 1:
     printf("输⼊操作数:");
     scanf("%d %d", &x, &y)
     ret = add(x, y);
     printf("ret = %d\n", r
     break;
     case 2:
     printf("输⼊操作数:");
     scanf("%d %d", &x, &y)
     ret = sub(x, y);
     printf("ret = %d\n", r
     break;
     case 3:
     printf("输⼊操作数:");
     scanf("%d %d", &x, &y)
     ret = mul(x, y);
     printf("ret = %d\n", r
     break;
     case 4:
     printf("输⼊操作数:");
     scanf("%d %d", &x, &y)
     ret = div(x, y);
     printf("ret = %d\n", r
     break;
     case 0:
     printf("退出程序\n");
     break;
     default:
     printf("选择错误\n");
     break;
     }
     } while (input);
     return 0;
    }
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67

    (2)使用回到函数改造后

    //使⽤回到函数改造后
    #include 
    int add(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 div(int a, int b)
    {
     return a / b;
    }
    void calc(int(*pf)(int, int))
    {
     int ret = 0;
     int x, y;
     printf("输⼊操作数:");
     scanf("%d %d", &x, &y);
     ret = pf(x, y);
     printf("ret = %d\n", ret);
    }
    int main()
    {
     int input = 1;
     do
     {
     printf("******************
     printf(" 1:add 
     printf(" 3:mul 
     printf("******************
     printf("请选择:");
     scanf("%d", &input);
     switch (input)
     {
     case 1:
     calc(add);
     break;
     case 2:
     calc(sub);
     break;
     case 3:
     calc(mul);
     break;
     case 4:
     calc(div);
     break;
     case 0:
     printf("退出程序\n");
     break;
     default:
     printf("选择错误\n");
     break;
     }
     } while (input);
     return 0;
    }
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62

    2.qsort使用举例

    #include 
    //qosrt函数的使⽤者得实现⼀个⽐较函数
    int int_cmp(const void * p1, const void * p2)
    {
     return (*( int *)p1 - *(int *) p2);
    }
    int main()
    {
     int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
     int i = 0;
     
     qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
     for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
     {
     printf( "%d ", arr[i]);
     }
     printf("\n");
     return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3. qsort函数的模拟实现

    由于在前面的博客里,qsort函数的模拟实现已经讲的非常详细了,所以这里我就简单写一下源码,不懂得可以去看我前面的博客学习怎样模拟实现qsort函数,感谢理解支持

    使用回调函数,模拟实现qsort(采用冒泡的方式)。
    注意:这里第一次使用 void* 的指针,讲解 void* 的作用。

    #include 
    int int_cmp(const void * p1, const void * p2)
    {
     return (*( int *)p1 - *(int *) p2);
    }
    void _swap(void *p1, void * p2, int size)
    {
     int i = 0;
     for (i = 0; i< size; i++)
     {
     char tmp = *((char *)p1 + i);
     *(( char *)p1 + i) = *((char *) p2 + i);
     *(( char *)p2 + i) = tmp;
     }
    }
    void bubble(void *base, int count , int size, int(*cmp )(void *, void *))
    {
     int i = 0;
     int j = 0;
     for (i = 0; i< count - 1; i++)
     {
     for (j = 0; j<count-i-1; j++)
     {
     if (cmp ((char *) base + j*size , (char *)base + (j + 1)*size) > 0)
     {
     _swap(( char *)base + j*size, (char *)base + (j + 1)*size, size);
     }
     }
     }
    }
    int main()
    {
     int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
     //char *arr[] = {"aaaa","dddd","cccc","bbbb"};
     int i = 0;
     bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
     for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
     {
     printf( "%d ", arr[i]);
     }
     printf("\n");
     return 0;
    }
    
    • 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
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43

    4.sizeof和strlen的对比

    4.1sizeof

    在学习操作符的时候,我们学习了 sizeof sizeof 计算变量所占内存内存空间大小的单位是字节,如果操作数是类型的话,计算的是使⽤类型创建的变量所占内存空间的大小。
    sizeof 只关注占⽤内存空间的大小,不在乎内存中存放什么数据。
    比如:

    #inculde <stdio.h>
    int main()
    {
     int a = 10;
     printf("%d\n", sizeof(a));
     printf("%d\n", sizeof a);
     printf("%d\n", sizeof(int));
     
     return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    4.2strlen

    strlen 是C语言库函数,功能是求字符串长度。函数原型如下:

    size_t strlen ( const char * str );
    
    • 1

    统计的是从 strlen 函数的参数 str 中这个地址开始向后, \0 之前字符串中字符的个数。
    strlen 函数会⼀直向后找 \0 字符,直到找到为止,所以可能存在越界查找。

    #include 
    int main()
    {
     char arr1[3] = {'a', 'b', 'c'};
     char arr2[] = "abc";
     printf("%d\n", strlen(arr1));
     printf("%d\n", strlen(arr2));
     
     printf("%d\n", sizeof(arr1));
     printf("%d\n", sizeof(arr1));
     return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4.3sizeof 和 strlen的对比

    sizeof

    1. sizeof是操作符
    2. sizeof计算操作数所占内存的大小,单位是字节
    3. 不关注内存中存放什么数据

    strlen

    1. strlen是库函数,使⽤需要包含头文件 string.h
    2. srtlen是求字符串长度的,统计的是 \0 之前字符的隔个数
    3. 关注内存中是否有 \0 ,如果没有 \0 ,就会持续往后找,可能会越界
  • 相关阅读:
    列化复杂的xml对应的类
    Ajax 实战
    C# 成为2023年度编程语言之王
    滚珠螺杆的螺母朝向反了能用吗?
    如何更改IP地址使用代理ip软件
    鸿蒙Harmony应用开发—ArkTS声明式开发(组件可见区域变化事件)
    基于深度学习的车道检测(一)
    大数据运维之MySQL备份及恢复
    【k8s连载系列】k8s介绍
    封装element的dialog组件
  • 原文地址:https://blog.csdn.net/qq_73900397/article/details/133513366