C语言——深度理解指针(5)

1. 回调函数是什么?

回调函数就是⼀个通过函数指针调⽤的函数。

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

下面我们用代码实现一个加法运算:

c 复制代码
int add(int a, int b)//加法运算
{
	return a + b;
}

void calc(int(*pf)(int, int))//用calc调用add函数
{
	int ret = 0;
	int x, y;
	scanf_s("%d %d", &x, &y);
	ret = pf(x, y);
	printf("%d\n", ret);
}

int main()
{
	calc(add);
	return 0;
}

上面代码中,我们没有直间使用add 函数,而是把add 的指针给了calc 函数,间接的调用了add函数。这就是回调函数。

2. qsort 使⽤举例

2.1 使⽤qsort函数排序整型数据

首先我们先来认识一下什么是qsort函数:qsort 是 C 标准库中提供的快速排序函数,用于对数组进行排序它能够对任意类型的数据进行排序 ,通过用户自定义的比较函数实现灵活的排序规则。

qsort函数的头文件stdlib

qsort函数,需要提供四个数据:

c 复制代码
void qsort(
    void *base,     // 数组首元素地址
    size_t nmemb,   // 数组元素个数
    size_t size,    // 每个元素的大小(字节)
    int (*compar)(const void *, const void *) // 比较函数的指针
);

用qsort函数进行升序运算

1、排序对象是int时

c 复制代码
#include <stdio.h>
#include <stdlib.h>//qsort函数的头文件
//qosrt函数的使⽤者得实现⼀个⽐较函数
int int_cmp(const void* p1, const void* p2)
{
	return (*(int*)p1 - *(int*)p2);    
	//因为p1和p2原先定义的时候是void*,所以不可以直接解引用,因为数组中元素类型是int,所以要先强制转化成int*后在解引用
}
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;
}

const void* p1: 指向数组中第一个待比较元素的指针。

const void* p2: 指向数组中第二个待比较元素的指针。

比较函数需返回整数(也就是p1指向的值-p2指向的值):

负数:第一个参数应排在第二个参数之前。

0:两参数相等。

正数:第一个参数应排在第二个参数之后

2、排序对象是char类型时

c 复制代码
#include <stdio.h>    // 用于输入输出
#include <stdlib.h>   // 用于qsort函数
// 比较函数,用于比较两个字符的大小
int compare_chars(const void* a, const void* b) {
    char char_a = *(const char*)a;
    char char_b = *(const char*)b;
    return char_a - char_b;
}
int main() 
{
    char arr[] = { 'd', 'a', 'c', 'b', 'e' };
    int size = sizeof(arr) / sizeof(arr[0]);
    qsort(arr, size, sizeof(char), compare_chars);// 使用 qsort 对字符数组进行排序
    for (int i = 0; i < size; i++)  // 打印排序后的字符数组
    {
        printf("%c ", arr[i]);
    }
        return 0;
}

3、排序对象是字符串类型时

c 复制代码
#include <stdio.h>    // 用于输入输出
#include <stdlib.h>   // 用于qsort函数
#include <string.h>   // 用于strcmp函数
int compareStrings(const void* p1, const void* p2) {
    // 将void指针转换为指向字符串指针的指针
    char str1[] = "* (char*)p1";
    char str2[] = "* (char*)p2";
    return strcmp(str1, str2);// 使用strcmp比较字符串
}
int main() 
{
    char* strings[] = {"banana","apple","orange","grape","pear"};// 定义一个字符串数组
    int numStrings = sizeof(strings) / sizeof(strings[0]);
    qsort(strings, numStrings, sizeof(char*), compareStrings);// 使用qsort对字符串数组进行排序
    for (int i = 0; i < numStrings; i++)
    {
        printf("%s\n", strings[i]);// 打印排序后的结果
    }
    return 0;
}

注意字符串比较要用:strcmp函数

4、排序对象是浮点型类型时

c 复制代码
#include <stdio.h>
#include <stdlib.h>
int compare_floats(const void *a, const void *b) // 浮点数比较函数
{
    float fa = *(const float*)a;
    float fb = *(const float*)b;
    // 处理浮点数精度问题
    if (fa < fb)
     {
     return -1;
     }
    if (fa > fb)
     {
     return 1;
     }
    return 0;
}
int main() {
    float numbers[] = {3.14f, 1.59f, 2.65f, 3.58f, 9.79f, 3.23f};
    int size = sizeof(numbers) / sizeof(numbers[0]);
    // 使用qsort排序
    qsort(numbers, size, sizeof(float), compare_floats);
    // 打印排序结果
    for (int i = 0; i < size; i++) 
    {
        printf("%.2f ", numbers[i]);
    }
    return 0;
}

2.2 使⽤qsort排序结构数据

排序对象是结构体函数

c 复制代码
#include <stdio.h>    // 用于输入输出
#include <stdlib.h>   // 用于qsort函数
#include <string.h>   // 用于strcmp函数
struct Stu //定义一个嵌套函数
{
	char name[20];//名字
	int age;//年龄
};
//比较函数:假设按照年龄来⽐较
int cmp_stu_by_age(const void* e1, const void* e2)
{
	return ((struct Stu*)e1)->age - ((struct Stu*)e2)->age;
}

//strcmp - 是库函数,是专⻔⽤来⽐较两个字符串的⼤⼩的
//比较函数:假设按照名字来⽐较
int cmp_stu_by_name(const void* e1, const void* e2)
{
	return strcmp( ((struct Stu*)e1)->name , ((struct Stu*)e2)->name );
}

//按照年龄来排序
void test2()
{
	struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };
	int sz = sizeof(s) / sizeof(s[0]);
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_age);
}

//按照名字来排序
void test3()
{
	struct Stu s[] = { {"zhangsan", 20}, {"lisi", 30}, {"wangwu", 15} };
	int sz = (sizeof(s) / sizeof(s[0]));
	qsort(s, sz, sizeof(s[0]), cmp_stu_by_name);
}

int main()
{
	test2();//按照年龄来排序
	test3();//按照名字来排序
	return 0;
}

补充:结构体成员访问操作符 -> (通过指针间接访问结构体变量的成员)

c 复制代码
struct Stu //定义一个嵌套函数
{
	char name[20];//名字
	int age;//年龄
};
int main()
{
	struct Stu s = { "zhangsan", 20 };
	struct Stu* x = &s;
	printf("%d\n", x->age);
	return 0;
}

. 操作符用于直接访问结构体变量的成员

c 复制代码
struct Stu //定义一个嵌套函数
{
	char name[20];//名字
	int age;//年龄
};
int main()
{
	struct Stu s[]= {"zhangsan", 20};
	printf("%d\n", s.age);
	return 0;
}
相关推荐
智闲电子设计2 小时前
STM32 定时器 PWM 实战:从呼吸灯到舵机控制
c语言·stm32·单片机·嵌入式硬件·学习
佳児素花痴╮3 小时前
树的基础知识与查找排序算法
数据结构·算法
郝学胜-神的一滴3 小时前
Python 高级编程 026:内置数据结构之骈文纵论
开发语言·数据结构·python·程序人生·软件工程
程序员老舅9 小时前
啃透 I2C 驱动开发,才算入门嵌入式 Linux 内核驱动
数据结构·驱动开发·b树·内核·嵌入式·嵌入式开发·i2c
lueluelue4710 小时前
LeetCode:链表
算法·leetcode·链表
橘子汽水16813 小时前
Leetcode 23,543合并K个升序链表,二叉树的直径
算法·leetcode·链表
huameinan狮子13 小时前
Adaboost算法原理与计算实例
算法
别怪我很水13 小时前
API中提供了VelocityTracker类用于计算触摸事件MotionEvent的速度,而其内部默认使用的方法就是最小二乘法,本 ...
算法·gitee·最小二乘法