『C语言初阶』第四章-指针(4)

 1.回调函数是什么?

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

        如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,被调用的函数就是回调函数。

        回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

        在上一节中我们所写的转移表中,我们虽然采用的是函数数组调用的形式,但是实际上是根据用户的输入来调取不同的函数,而我们今天学习了回调函数后,就可以把函数数组的部分优化掉,只采用一个函数作为接口,然后根据函数指针参数,调取不同的函数,更加的直观,简便。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
void menu()

{

    puts("*********************************");

    puts("**********1.add   2.sub********");

    puts("*********************************");

    puts("**********3.mul   4.div********");

    puts("*********************************");

    puts("**************0.exit*************");

    puts("*********************************");

}

int Add(int x, int y)

{

    return x + y;

}

int Sub(int x, int y)

{

    return x - y;

}

int Mul(int x, int y)

{

    return x * y;

}

int Div(int x, int y)

{

    return x / y;

}

//接口函数
void calc(int (*pf)(int, int))
{
    printf("输入操作数:");
    int x, y;
    scanf("%d %d", &x, &y);
    int ret = pf(x, y);
    printf("%d\n", ret);
}


int main()

{

    menu();

    int x, y;
    int input;

    do

    {
        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);
        case 0:
            break;
        default:
            printf("选择错误\n");
            break;
        }

    } while (input);
}

2.qsort()使用举例

        qsort是c语言中stdlib.h库中的一个排序函数,可以根据我们所给的参数,排列大小,底层实现是快速排序,通过下面的参数,我们可以看到void* 说明qsort 函数是适用于所有任意类型的函数

        base: 指向要排序的数组的第一个对象的指针

        num: 数组中排序的元素数量

        size: 数组中每个元素的大小(以字节为单位)

        compar: 指向两个元素的函数指针

         将两个指针作为参数(均转化为const void*)。函数通过返回定义元素的顺序:

        

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

//这里需要注意参数,最好写成const void* 的形式 适配其他类型
int int_cmp(const void* p1, const void* p2)
{
	return (*(int*)p1) - (*(int*)p2);
}

int main()
{
	int arr[] = { 1,3,5,4,8,9,12,2,3 };
	int i = 0;
	size_t sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), int_cmp);
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

2.2使用qsort 排序结构数据

struct Stu
{
	char name[20];
	int age;
};

int cmp_stu_by_age(const void* p1, const void* p2)
{
	return (*(struct Stu*)p1).age - (*(struct Stu*)p2).age;
}

int cmp_stu_by_name(const void* p1, const void* p2)
{
	return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->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_name);
	for (int i = 0; i < sz; i++)
	{
		printf("%s\t", s[i].name);
		printf("%d\n", s[i].age);
	}
}


void test1()
{
	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);
	for (int i = 0; i < sz; i++)
	{
		printf("%s\t", s[i].name);
		printf("%d\n", s[i].age);
	}

}

int main()
{
	test1();  //按照年龄排序
	printf("\n");
	test2();  //按照名字排序
	return 0;
}

需要注意 strcmp 是string.h的库函数,专门用来比较两个字符串的大小的,且比较的是字典序,也就是依次比较ASCII码,返回值正好与我们构建的函数返回值规则一致。

3. qsort函数的模拟实现

        使用回调函数,模拟实现qsort(采用冒泡的方式)

        基本核心:

void qsort(
	void* base,//base 指向了要排序的数组的第一个元素
	size_t num, //base指向的数组中的元素个数(待排序的数组的元素的个数)
	size_t size,//base指向的数组中元素的大小(单位是字节)
	int (*compar)(const void* p1, const void* p2)//函数指针 - 指针指向的函数是用来比较数组中的2个元素的
)
{
	if (compar(x, y) > 0)
	{
		//交换
	}
}

 实现代码:

        注意其中的字节交换,以及排序时对于元素的变更,都是怎么具体实现的

void swap(void* p1, void* p2,size_t size)
{
	//由于不知道类型,所以需要根据参数类型,一个一个字节交换字节里的值来达到元素交换的效果

	for (int i = 0; i < size; i++)
	{
		char temp = *((char*)p1+i);
		*((char*)p1+i) = *((char*)p2+i);
		*((char*)p2 + i) = temp;
	}
}
int int_cmp(const void * p1, const void* p2)
{
	return (*(int*)p1 - *(int*)p2);
}
//size_t 是字节类型 是无符号整型数据
void bubble(void* base, int count, size_t size, int (*cmp)(const void*, const void*))
{
	int i, j;
	i = j = 0;
	for (i = 0; i < count-1; i++)
	{
		for (j = 0; j < count - i - 1; j++)
		{
			//因为我们不知道传入的数组是什么类型的
		   // 所以就需要转成char* 然后移动 j*size来移动指针来达到选其他数组元素的目的
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size)>0) // 大于0 说明 前者大于后者
			{ 
				swap((char*)base + j * size, (char*)base + (j + 1) * size,size);
			}
		}
	}
}

int main()
{
	int arr[] = { 1,3,5,4,8,9,12,2,3 };
	int i = 0;
	int sz = sizeof arr / sizeof arr[0];
	bubble(arr,sz , sizeof(int), int_cmp);
	for (int i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
	return 0;
}

相关推荐

  1. C语言--指针

    2024-02-23 18:36:01       9 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-02-23 18:36:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-02-23 18:36:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-02-23 18:36:01       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-02-23 18:36:01       20 阅读

热门阅读

  1. 汇编英文全称

    2024-02-23 18:36:01       27 阅读
  2. uni-app中组件和样式的使用

    2024-02-23 18:36:01       26 阅读
  3. TypeScript基础知识点

    2024-02-23 18:36:01       24 阅读
  4. 超参数优化

    2024-02-23 18:36:01       20 阅读
  5. 【无标题】

    2024-02-23 18:36:01       29 阅读
  6. 第10章 搭建网盘服务

    2024-02-23 18:36:01       23 阅读
  7. Linux第64步_编译移植好的虚拟机文件

    2024-02-23 18:36:01       24 阅读
  8. npm install报错,解决记录

    2024-02-23 18:36:01       28 阅读
  9. vue+electron 修改默认安装目录

    2024-02-23 18:36:01       26 阅读
  10. 听课笔记03

    2024-02-23 18:36:01       23 阅读