c语言从入门到实战——回调函数与qsort的讲解和模拟实现

news2025/1/11 2:24:59

回调函数与qsort的讲解和模拟实现

  • 前言
  • 1. 回调函数是什么?
  • 2. qsort
    • 2.1 使用qsort函数排序整型数据
    • 2.2 使用qsort排序结构数据
  • 3. qsort函数的模拟实现


前言

回调函数是一个函数,它作为参数传递给另一个函数,并且能够在该函数内部被调用。在C语言中,回调函数通常被用于实现事件处理和排序算法中。

qsort是C标准库中的一个排序函数,它可以对任意类型的数组进行排序。qsort需要三个参数:要排序的数组、数组元素的个数和一个指向回调函数的指针。回调函数必须满足两个条件:能够比较数组中的元素,返回一个整数表示它们之间的大小关系;并且它应该能够被qsort函数调用。


1. 回调函数是什么?

C语言中,回调函数是指将一个函数作为参数传递给另一个函数,并在后者中被调用的函数。

一般情况下,回调函数被用来在程序中实现事件处理和消息传递等机制。例如,当一个用户在应用程序中点击一个按钮时,应用程序会调用相应的回调函数来处理该事件。

以下是一个示例代码,展示了如何在C语言中定义和使用回调函数:

#include <stdio.h>

// 回调函数定义
typedef int (*callback)(int);

// 回调函数实现
int callback_function(int num) {
    return num * 2;
}

// 接收回调函数参数的函数
void accept_callback(int num, callback cb) {
    int result = cb(num); // 调用回调函数
    printf("The result is: %d\n", result);
}

int main() {
    // 调用 accept_callback 函数,并传入回调函数指针
    accept_callback(5, callback_function);

    return 0;
}

在上述示例中,我们通过定义 callback 类型为函数指针类型,从而定义了一个回调函数类型。接着,我们定义了回调函数 callback_function,该函数接收一个整数作为参数,并返回该参数的两倍。最后,我们通过调用 accept_callback 函数,并传入一个整数以及回调函数的指针,实现了回调函数的调用和结果输出。

需要注意的是,回调函数的实现和使用需要满足一定的约定,例如回调函数的参数和返回值类型需要与被调用函数的要求一致,否则会导致程序运行错误。

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

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

//使用回调函数改造前
#include <stdio.h>
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("******************\n");
	printf(" 1:add  2:sub     \n");
	printf(" 3:mul  4:div     \n");
	printf("******************\n");
	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;
}
//使用回到函数改造后
#include <stdio.h>
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;
	printf("******************\n");
	printf(" 1:add  2:sub     \n");
	printf(" 3:mul  4:div     \n");
	printf("******************\n");
	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;
}

2. qsort

在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/a775e1216eb84ac0b69764becda26310.png
在这里插入图片描述
)

qsort是C语言中的一个标准库函数,用于实现快速排序算法。它可以对任意类型的数组进行排序,只需要给出相应的比较函数即可。

qsort的函数原型如下:

void qsort(void *base, size_t nmemb, size_t size,
           int (*compar)(const void *, const void *));

其中,base是要排序的数组的首地址,nmemb是数组中元素的个数,size是每个元素的大小(以字节为单位),compar是用来比较数组中元素大小的函数指针。

比较函数的定义如下:

int compar(const void *a, const void *b);

函数需要返回一个整型值,表示两个元素的大小关系。如果a小于b,返回一个负数;如果a等于b,返回0;如果a大于b,返回一个正数。

下面是一个使用qsort进行int类型数组排序的例子:

#include <stdio.h>
#include <stdlib.h>

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

int main() {
    int arr[] = {3, 1, 4, 1, 5, 9, 2, 6};
    int n = sizeof(arr) / sizeof(int);

    qsort(arr, n, sizeof(int), cmp);

    for (int i = 0; i < n; i++) {
        printf("%d ", arr[i]);
    }
    printf("\n");

    return 0;
}
运行结果为:1 1 2 3 4 5 6 9

上述代码中,我们定义了一个比较函数cmp,返回a-b的结果,然后将其传给qsort函数进行排序。在main函数中,我们定义了一个int类型的数组arr,调用qsort进行排序后,输出结果即可。

需要注意的是,qsort函数是一个不稳定的排序算法,即排序后可能改变数组中相同元素的原有顺序。

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

#include <stdio.h>
//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;
}

2.2 使用qsort排序结构数据

#include <stdio.h>
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;
}

3. qsort函数的模拟实现

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

#include <stdio.h> 
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 };
	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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1232395.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

优秀智慧园区案例 - 佛山美的工业城零碳智慧园区,先进智慧园区建设方案经验

一、项目背景 美的工业园区西区最早建于上世纪90年代&#xff0c;到现在已经过去近30年&#xff0c;而这三十年恰恰是信息科技大发展的30年&#xff0c;原有的生产办公条件已不能很好的承载新时期办公和参观接待的需求。所以在21年美的楼宇科技事业部决定对原来的园区进行改造…

工具及方法 - 多邻国: Duolingo

网站&#xff1a;Duolingo 有iOS和Android应用&#xff0c;在App Store和Google Play上都能下载。也可以使用网页版。我就在iOS上安装了付费版&#xff0c;为了小朋友学习英语&#xff0c;一年的费用&#xffe5;588。 目前学习中的课程是英语、日语和粤语。英语是小学课程&a…

Linux shell编程学习笔记28:脚本调试 set命令

0 引入 在Linux Shell 脚本编程的过程中&#xff0c;编写简单功能的脚本&#xff0c;代码不多&#xff0c;一般阅读起来没什么难度&#xff0c;有问题也比较有查出原因和修正。但是当脚本要实现的功能较多&#xff0c;代码变得较为复杂时&#xff0c;阅读起来就不那么容易看明…

macos苹果电脑清理软件有哪些?cleanmymac和腾讯柠檬哪个好

MacOS是一款优秀的操作系统&#xff0c;但是随着使用时间的增加&#xff0c;它也会产生一些不必要的垃圾文件&#xff0c;占用磁盘空间和内存资源&#xff0c;影响系统的性能和稳定性。为了保持MacOS的清洁和高效&#xff0c;我们需要使用一些专业的清理软件来定期扫描和清除这…

深入探索 PaddlePaddle 中的计算图

**引言** 计算图是深度学习平台 PaddlePaddle 的核心组件之一&#xff0c;它提供了一种图形化的方式来表示和执行深度学习模型。通过了解和理解 PaddlePaddle 中的计算图&#xff0c;我们可以更好地理解深度学习的工作原理&#xff0c;并且能够更加灵活和高效地构建和训练复杂…

QT基础学习

2创建项目 2.1使用向导创建 打开Qt Creator 界面选择 New Project或者选择菜单栏 【文件】-【新建文件或项目】菜单项 弹出New Project对话框&#xff0c;选择Qt Widgets Application&#xff0c; 选择【Choose】按钮&#xff0c;弹出如下对话框 设置项目名称和路径&#xf…

11.15 监控目录文件变化

监视对指定目录的更改&#xff0c;并将有关更改的信息打印到控制台&#xff0c;该功能的实现不仅可以在内核层&#xff0c;在应用层同样可以。程序中使用ReadDirectoryChangesW函数来监视目录中的更改&#xff0c;并使用FILE_NOTIFY_INFORMATION结构来获取有关更改的信息。 Re…

requests库出现AttributeError问题的修复与替代方法

在使用App Engine时&#xff0c;开发者们通常会面临需要发送爬虫ip请求的情况&#xff0c;而Python中的requests库是一个常用的工具&#xff0c;用于处理爬虫ip请求。然而&#xff0c;在某些情况下&#xff0c;开发者可能会遇到一个名为AttributeError的问题&#xff0c;特别是…

适合您的智能手机的 7 款优秀手机数据恢复软件分享

如今&#xff0c;我们做什么都用手机&#xff1b;从拍照到录音&#xff0c;甚至作为 MP3 播放器&#xff0c;我们已经对手机变得非常依恋。这导致我们在手机上留下了很多珍贵的回忆。 不幸的是&#xff0c;我们有可能会丢失手机上的部分甚至全部数据。幸运的是&#xff0c;这不…

【练习】检测U盘并自动复制内容到电脑的软件

软件作用&#xff1a; 有U盘插在电脑上后&#xff0c;程序会检测到U盘的路径。 自己可以提前设置一个保存复制文件的路径或者使用为默认保存的复制路径&#xff08;默认为桌面&#xff0c;可自行修改&#xff09;。 检测到U盘后程序就会把U盘的文件复制到电脑对应的…

C#,数值计算——插值和外推,分段线性插值(Linear_interp)的计算方法与源程序

1 文本格式 using System; namespace Legalsoft.Truffer { /// <summary> /// 分段线性插值 /// Piecewise linear interpolation object. /// Construct with x and y vectors, then call interp for interpolated values. /// </summary> …

C#,怎么修改(VS)Visual Studio 2022支持的C#版本

一些文字来自于 Microsoft . &#xff08;只需要读下面的红色文字即可&#xff01;&#xff09; 1 C# 语言版本控制 最新的 C# 编译器根据项目的一个或多个目标框架确定默认语言版本。 Visual Studio 不提供用于更改值的 UI&#xff0c;但可以通过编辑 .csproj 文件来更改值。…

(二)汇编语句组成

一个完整的 RISC-V 汇编程序有多条 语句&#xff08;statement&#xff09; 组成。 一条典型的 RISC-V 汇编 语句 由 3 部分组成&#xff1a; 1.标签 List item label&#xff08;标签&#xff09;: 标签是标识程序位置的记号。通常定义一个名称然后加上":"后缀。…

【图像分类】【深度学习】【轻量级网络】【Pytorch版本】MobileNets_V2模型算法详解

【图像分类】【深度学习】【轻量级网络】【Pytorch版本】MobileNets_V2模型算法详解 文章目录 【图像分类】【深度学习】【轻量级网络】【Pytorch版本】MobileNets_V2模型算法详解前言MobleNet_V2讲解反向残差结构(Inverted Residuals)兴趣流形(Manifold of interest)线性瓶颈层…

Python - Wave2lip 环境配置与 Wave2lip x GFP-GAN 实战 [超详细!]

一.引言 前面介绍了 GFP-GAN 的原理与应用&#xff0c;其用于优化图像画质。本文关注另外一个相关的项目 Wave2lip&#xff0c;其可以通过人物视频与自定义音频进行适配&#xff0c;改变视频中人物的嘴型与音频对应。 二.Wave2Lip 简介 Wave2lip 研究 lip-syncing 以达到视频…

PyTorch微调终极指南2:提升模型的准确性

作为一名机器学习从业者&#xff0c;你可能经常会发现自己处于这样一种情况&#xff1a;你正在针对特定任务微调预先训练的模型&#xff0c;但已经达到了无法进一步提高模型准确性的地步。 在本文中&#xff0c;我们将探讨可用于提高模型准确性的各种技术和策略。 这些方法旨在…

代码随想录算法训练营Day36 —— 435. 无重叠区间、763.划分字母区间、56. 合并区间

435. 无重叠区间 思路&#xff1a; 按照左边排序&#xff0c;按照452引爆气球的思路即可&#xff0c;统计重叠区间个数就是最小删除个数&#xff0c; 直接改点就好。 代码&#xff1a; //手搓 class Solution { private:static bool cmp(const vector<int>& a, c…

从0开始学习JavaScript--深入探究JavaScript类型化数组

JavaScript类型化数组是一种特殊的数组类型&#xff0c;引入了对二进制数据的更底层的操作。这种数组提供了对内存中的二进制数据直接进行读写的能力&#xff0c;为处理图形、音频、视频等大规模数据提供了高效的手段。本文将深入探讨JavaScript类型化数组的基本概念、常见类型…

代码随想录算法训练营第六十天丨 单调栈03

84.柱状图中最大的矩形 思路 单调栈 本地单调栈的解法和接雨水的题目是遥相呼应的。 为什么这么说呢&#xff0c;42. 接雨水 (opens new window)是找每个柱子左右两边第一个大于该柱子高度的柱子&#xff0c;而本题是找每个柱子左右两边第一个小于该柱子的柱子。 这里就涉…

机器人制作开源方案 | 智能照科植物花架

作者&#xff1a;付菲菲、于海鑫、王子敏单位&#xff1a;黑河学院指导老师&#xff1a;索向峰、李岩 1. 概述 1.1设计背景​ 随着时代的发展&#xff0c;城市化脚步加快、城市人口密度越来越大、城市生活节奏快压力大作息难成规律。城市建筑建筑面积迅速增加、而绿…