c语言------指针(4)

本文介绍了函数指针数组的概念,展示了如何使用函数指针数组实现回调函数,并详细讲解了C语言标准库函数qsort的使用和模拟冒泡排序的实现,重点讨论了如何在不同数据类型上进行排序操作。
摘要由CSDN通过智能技术生成

目录

函数指针数组

回调函数

qsort

 qosrt的使用举例

qsort的模拟实现


函数指针数组

在指针(3)中已经提到了函数指针的概念,接下来我们直接学习函数指针数组。

函数指针数组其实就是:声明一个数组,里面存储的类型是,指向函数的指针。

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;
}

int main()
{

     //函数指针
    /*int(*pf)(int, int) = add;*/

     //函数指针数组
    int(*pf[4])(int, int) = {add, sub, mul,div};//存放函数指针的数组--函数指针数组

    for (int i = 0; i < 4; i++)//通过数组元素调用函数

    {
        int t=pf[i](1,1);
        printf("%d\n", t);
    }
}

回调函数

什么是回调函数?

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

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

例如,我们写一个代码实现计算器的功能:

大部分都会写出和下面类似的代码:

#include<stdio.h>

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 menu()
{
	printf("***********************************\n");
	printf("**********1.add******2.sub*********\n");
	printf("**********3.mul******4.div*********\n");
	printf("***********************************\n");
}


int main()
{
	int input;
	int x, y;
	int t;
	do
	{
		menu();
		printf("请选择操作:\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			printf("请输入要操作的数:\n");
			scanf("%d%d", &x, &y);
			t = add(x, y);
			printf("%d\n", t);
			break;
		case 2:
			printf("请输入要操作的数:\n");
			scanf("%d%d", &x, &y);
			t = sub(x, y);
			printf("%d\n", t);
			break;
		case 3:
			printf("请输入要操作的数:\n");
			scanf("%d%d", &x, &y);
			t = mul(x, y);
			printf("%d\n", t);
			break;
		case 4:
			printf("请输入要操作的数:\n");
			scanf("%d%d", &x, &y);
			t = div(x, y);
			printf("%d\n", t);
			break;
		case 0:
			printf("退出!\n");
			break;
		default:
			printf("输入不合理!请重新输入\n");
			break;
		}
	} while (input != 0);

}

我们发现在主函数里面出现了相似的代码:

printf("请输入要操作的数:\n");
            scanf("%d%d", &x, &y);
            t = add(x, y);
            printf("%d\n", t);

这样看会显得我们写的代码过于冗余,那怎么简化一下呢?

我们发现在相似的代码里面,只有函数调用时出现了不同,我们可以把函数调用的地址以参数的形式传递过去,使用函数指针接收,函数指针指向什么函数就调用什么函数;

#include<stdio.h>

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 menu()
{
	printf("***********************************\n");
	printf("**********1.add******2.sub*********\n");
	printf("**********3.mul******4.div*********\n");
	printf("***********************************\n");
}

void fun(int (*pf)(int,int))
{
	int x, y;
	int t;
	printf("请输入要操作的数:\n");
	scanf("%d%d", &x, &y);
	t =pf(x, y);
	printf("%d\n", t);
}

int main()
{
	int input;
	
	do
	{
		menu();
		printf("请选择操作:\n");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			fun(add);
			break;
		case 2:
			fun(sub);
			break;
		case 3:
			fun(mul);
			break;
		case 4:
			fun(div);
			break;
		case 0:
			printf("退出!\n");
			break;
		default:
			printf("输入不合理!请重新输入\n");
			break;
		}
	} while (input!=0);
	
}

回调函数:

void fun(int (*pf)(int,int))
{
    int x, y;
    int t;
    printf("请输入要操作的数:\n");
    scanf("%d%d", &x, &y);
    t =pf(x, y);
    printf("%d\n", t);
}

qsort

qsort是一个库函数,可以直接使用,用来任意类型数据的排序;

声明:
void qsort (void* base, size_t num, size_t size, int (*compar)(const void*,const void*));

void qsort(
    void* base,//base指向了排序数组中的第一个元素
    size_t num,//base指向的数组中的元素个数
    size_t size,//base指向的数组中的元素大小(单位是字节)
    int(*compar)(const void* p1, const void* p2)//比较方式
);

 qosrt的使用举例

 排序整型数据:

int com(const void* p1, const void* p2)
{
    return (*(int*)p1) - (*(int*)p2);
    //如果p1>p2,那么p1-p2的值大于0,返回值大于0;
    //如果p1<p2,那么返回值小于0;
}

void Print(int arr[],int sz)//打印数组
{
    for (int i = 0; i < sz; i++)
        printf("%d ", arr[i]);
}
void test1()
{
    int arr[10] = { 1,3,2,4,6,5,0,9,8,7 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    qsort(arr, sz, sizeof(arr[0]), com);//实现的是升序
    Print(arr, sz);
}

排序结构体数据:

struct stu
{
    char name[20];
    int age;

};

//按年龄来比较

int com_age(const void* p1, const void* p2)
{
    return ((struct stu*)p1)->age - ((struct stu*)p2)->age;
}

//按名字来比较
int com_name(const void* p1, const void* p2)
{
    return strcmp((struct stu*)p1, (struct stu*)p2);
}


void Print1(struct stu arr[], int sz)//打印
{
    for (int i = 0; i < sz; i++)
        printf("%s %d    ", arr[i].name,arr[i].age);
    printf("\n");
}


void test2()
{
    struct stu st[] = { {"Li",23},{"Wang",24},{"Yang",20} };
    int sz = sizeof(st) / sizeof(st[0]);
    qsort(st, sz, sizeof(st[0]), com_age);
    Print1(st, sz);
    qsort(st, sz, sizeof(st[0]), com_name);
    Print1(st, sz);
}

qsort的模拟实现

我们先写一个冒泡排序,在冒泡排序的前提下模拟实现qsort:

void bubble_sort(int arr[], int sz)//参数要重新设计
{
    for (int i = 0; i < sz; i++)
    {
        for (int j = 0; j <sz-1-i ; j++)
        {
            if (arr[j] > arr[j + 1])//比较的地方要使用回调函数改造
            {
                int t = arr[j];
                arr[j] = arr[j + 1];//交换代码也需要改造
                arr[j + 1] = t;
            }
        }
    }
}

 由于我们使用的冒泡排序传递的参数是数组,不能给除数组外的其他类型数据(如结构体等)排序,这里我们使用void* base,以指针作为参数进行传递;

我们传递的参数是指针类型,我们就需要考虑如何用指针来表示arr[j] ,这里我们就需要引入一个新的参数:width,即:(char *)base+j*width;

这样我们就可以表示if (arr[j] > arr[j + 1])cmp((char *)base + j * width, (char*)base + (j + 1) * width)>0,这里传递cmp函数即可;

int(*cmp)(const void *p1,const void *p2)

如何交换呢:可以一个字节一个字节的交换,这样如果是结构体数据类型,也可以通用;

最后就是如何设计来实现交换:

void swap(char *b1,char *b2,int width)
{
    for (int i = 0; i < width; i++)
    {
        char tmp = *b1;
        *b1 = *b2;
        *b2 = tmp;
        b1++;
        b2++;
    }

}

修改后 :

int com(const void* p1, const void* p2)
{
    return *(int*)p1 - *(int*)p2;
}

void swap(char *b1,char *b2,int width)
{
    for (int i = 0; i < width; i++)
    {
        char tmp = *b1;
        *b1 = *b2;
        *b2 = tmp;
        b1++;
        b2++;
    }

}

void bubble_sort2(void *base,size_t sz,size_t width,int(*cmp)(const void *p1,const void *p2))
{
    for (int i = 0; i < sz; i++)
    {
        for (int j = 0; j < sz - 1 - i; j++)
        {
            //if (arr[j] > arr[j + 1])
            if (cmp((char *)base + j * width, (char*)base + (j + 1) * width)>0)
            {
                /*int t = arr[j];
                arr[j] = arr[j + 1];
                arr[j + 1] = t;*/
                swap((char*)base + j * width, (char*)base + (j + 1) * width,width);
            }
        }
    }
}

void test3()
{
    int arr[] = { 3,1,2,4,5,7,6,0,9,8 };
    int sz = sizeof(arr) / sizeof(arr[0]);
    bubble_sort2(arr, sz,sizeof(arr[0]),com);

    Print(arr, sz);
}

  • 20
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值