椋鸟C语言笔记#22:回调函数、泛式编程、qsort

萌新的学习笔记,写错了恳请斧正。


目录

回调函数

泛式编程

qsort

qsort是什么

比较函数怎么写

使用qsort排序各种数据

模仿qsort写一个万能冒泡排序


回调函数

当一个函数a的参数含有函数指针时,这个函数指针在使用时所指向的函数b(被该函数调用的函数)就是回调函数。注意回调函数并不是由函数a决定调用的函数,而是在调用函数a时决定使用的函数。

比方说,上一篇笔记中的计算器如果不用转移表实现,也可以这样:

#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**2:sub**********");      
        printf("**3:mul**4:div**0:exit**");         
        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;
}

上方的calc函数的参数就是函数指针,在实际调用calc函数时提供的指针指向的函数就是回调函数

泛式编程

泛式编程就是在编程的时候尽量减少对特定数据类型的依赖

比方说我们要写一个冒泡排序的函数,如下:

void sortofup(int s[], int n)
{
	_Bool flag = true;
	while (flag)
	{
		flag = false;
		for (int i = 0; i < n - 1; i++)
			if (s[i] > s[i + 1])
			{
				s[i] ^= s[i + 1];
				s[i + 1] ^= s[i];
				s[i] ^= s[i + 1];
				flag = true;
			}
	}
}

上面就是对一个长度为n的数组的冒泡排序的实现

但是这个数组只能是整型数组。如果我们需要对浮点型数组排序,就需要再写一个浮点型数组的冒泡排序;如果我们要对长整型数组排序,就需要再写一个长整型数组的冒泡排序。这就十分死板

而在库函数中,有一个函数叫qsort,它能对任意类型的数据进行快速排序,十分灵活

这就是泛式编程的应用,那么具体是怎么实现的呢?不急,待会讲。

qsort

qsort是什么

qsort是stdlib.h(或search.h)头文件中定义的一种排序函数

qsort没有返回值(void),而其参数有4个:

  1. void* base:指向需要排序的数组的首元素的指针base(注意前面笔记讲过void*类型的参数可以接受任意类型的指针传参,但是使用时需要先强制类型转换
  2. size_t num:需要排序的数据的数量
  3. size_t width:需要排序的数据中每个数据占多少字节
  4. int (*compare)(void*, void*):一个函数指针compare,指向一个返回值为整型参数为两个泛型指针变量的函数。这就是比较函数。
比较函数怎么写

在使用qsort时,我们需要排序某种类型的数据,就先写一个对该类型数据的比较函数。这个函数的参数是两个泛型指针,返回值是整型,而返回值的正负或零代表了比较的结果是大于小于或等于(第一个参数更大时返回正数则递增排序,反之则为递减排序,如果有其他比较排序规则也可以自行添加,比如奇偶交叉等)。比方说,比较两个整型数据,我们可以这么写:

int Comp_int(const void* a, const void* b)
{
    int ia = *(int*)a;
    int ib = *(int*)b;
	if (ia > ib)
        return 1;
    if (ia < ib)
        return -1;
    else
        return 0;
}

上方代码我们将a与b强制类型转换为整型指针并解引用,这样我们就得到了整型a与b的值,并可以加以比较。

注意如果指针传参时我们不希望原值被改变,无论函数中有没有会对原值产生影响的内容,我们都最好在参数前加一个const进行限制,这是一个好习惯。 

我们也可以进一步根据实际情况简化比较函数:

int Comp_int(void* a, void* b)
{
	return *(int*)a - *(int*)b;
}
使用qsort排序各种数据
#include 
#include 
#include 
#include 

struct Stu
{
	char Name[20];
	short ID;
};

int Comp_int(void* a, void* b)
{
	return *(int*)a - *(int*)b;
}

int Comp_flt(void* a, void* b)
{
	int c = 0;
	if ((c = *(float*)a - *(float*)b) == 0)
		return 0;
	return c > 0 ? 1 : -1;
}

int Comp_struct_by_ID(void* a, void* b)
{
	return ((struct Stu*)a)->ID - ((struct Stu*)b)->ID;
}

int main()
{
    //@@@@@排序整型数组并打印@@@@@
	int arr_int[] = { 2,5,78,3,31,6,7865,34,1,7,8,132,4,7,5 };
	size_t len_int = sizeof arr_int / sizeof arr_int[0];
	qsort(arr_int, len_int, sizeof arr_int[0], Comp_int);
	for (int i = 0; i < len_int; i++)
		printf("%d ", arr_int[i]);
	printf("\n");

    //@@@@@排序浮点型数组并打印@@@@@
	float arr_flt[] = { 12.5,3.5,6.2,9,1.1,98.2,0.4,-9.3,14.7 };
	size_t len_flt = sizeof arr_flt / sizeof arr_flt[0];
	qsort(arr_flt, len_flt, sizeof arr_flt[0], Comp_flt);
	for (int i = 0; i < len_flt; i++)
		printf("%.2f ", arr_flt[i]);
	printf("\n");

    //@@@@@排序结构体数组并打印@@@@@
	struct Stu arr_struct[] = { {"zhangsan",2},{"lisi",1},{"wangwu",3} };
	size_t len_struct = sizeof arr_struct / sizeof arr_struct[0];
        //按id排序
	qsort(arr_struct, len_struct, sizeof arr_struct[0], Comp_struct_by_ID);
	for (int i = 0; i < len_struct; i++)
		printf("%s %hd ", arr_struct[i].Name, arr_struct[i].ID);
	printf("\n");
        //按首字母排序
	qsort(arr_struct, len_struct, sizeof arr_struct[0], strcmp);
	for (int i = 0; i < len_struct; i++)
		printf("%s %hd ", arr_struct[i].Name, arr_struct[i].ID);
	printf("\n");


	return 0;
}

上方代码按首字母排序的strcmp函数后面笔记会讲,是string.h提供的函数

模仿qsort写一个万能冒泡排序

我们可以模仿qsort来实现一个万能的冒泡排序

只需要做三件事:

  • 将其中比较数据大小的地方替换为比较函数的函数指针
  • 将指针变成char*类型(只占一个字节),然后利用数据数量与数据长度来定位指定数据
  • 将交换数据的地方处理为逐字节替换(利用第二点的定位)

具体实现如下:

#include 
#include 
#include 

struct Stu
{
	char Name[20];
	short ID;
};

int Comp_int(void* a, void* b)
{
	return *(int*)a - *(int*)b;
}

int Comp_flt(void* a, void* b)
{
	int c = 0;
	if ((c = *(float*)a - *(float*)b) == 0)
		return 0;
	return c > 0 ? 1 : -1;
}

int Comp_struct_by_ID(void* a, void* b)
{
	return ((struct Stu*)a)->ID - ((struct Stu*)b)->ID;
}

 
void bsort(void* base, size_t count, size_t size, int(*comp_f)(void*, void*))
{
	int flag = 1;
	for (int k = 0; k < count; k++)
	{
		flag = 1;
		for (int i = 0; i < count - k - 1; i++)
		{
			if (comp_f((char*)base + size * i, (char*)base + size * (i + 1)) > 0)
			{
				for (int j = 0; j < size; j++)
				{
					char* a = (char*)base + size * i + j;
					char* b = (char*)base + size * (i + 1) + j;
					char c;
					c = *a, *a = *b, *b = c;
				}
				flag = 0;
			}
		}
		if (flag)
			break;
	}
}


int main()
{
	int arr_int[] = { 2,5,78,3,31,6,7865,34,1,7,8,132,4,7,5 };
	size_t len_int = sizeof arr_int / sizeof arr_int[0];
	bsort(arr_int, len_int, sizeof arr_int[0], Comp_int);
	for (int i = 0; i < len_int; i++)
		printf("%d ", arr_int[i]);
	printf("\n");

	float arr_flt[] = { 12.5,3.5,6.2,9,1.1,98.2,0.4,-9.3,14.7 };
	size_t len_flt = sizeof arr_flt / sizeof arr_flt[0];
	bsort(arr_flt, len_flt, sizeof arr_flt[0], Comp_flt);
	for (int i = 0; i < len_flt; i++)
		printf("%.2f ", arr_flt[i]);
	printf("\n");

	struct Stu arr_struct[] = { {"zhangsan",2},{"lisi",1},{"wangwu",3} };
	size_t len_struct = sizeof arr_struct / sizeof arr_struct[0];
	bsort(arr_struct, len_struct, sizeof arr_struct[0], Comp_struct_by_ID);
	for (int i = 0; i < len_struct; i++)
		printf("%s %hd ", arr_struct[i].Name, arr_struct[i].ID);
	printf("\n");
	bsort(arr_struct, len_struct, sizeof arr_struct[0], strcmp);
	for (int i = 0; i < len_struct; i++)
		printf("%s %hd ", arr_struct[i].Name, arr_struct[i].ID);
	printf("\n");

	return 0;
}

你可能感兴趣的:(C语言笔记,笔记,c语言,开发语言)