【C语言】10.C语言指针(4)

文章目录

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


1.回调函数是什么?

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

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

使用回调函数改造前:

#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;
}
/*****************************************************main函数******************************************************/
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", 
                       ret);
                break;
            case 2:
                printf("输入操作数:");
                scanf("%d %d", &x, 
                      &y);
                ret = sub(x, y);
                printf("ret = %d\n", 
                       ret);
                break;
            case 3:
                printf("输入操作数:");
                scanf("%d %d", &x, 
                      &y);
                ret = mul(x, y);
                printf("ret = %d\n", 
                       ret);
                break;
            case 4:
                printf("输入操作数:");
                scanf("%d %d", &x, 
                      &y);
                ret = div(x, y);
                printf("ret = %d\n", 
                       ret);
                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;
}

/*****************************************************calc函数******************************************************/
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);
}

/*****************************************************main函数******************************************************/
int main(){
    int input = 1;
    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:
                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 使⽤举例

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

qsort是C语言中的一个库函数。

使用qsort函数要包含一个头文件:#include <stdlib.h>

这个函数是用来对数据进行排序的,对任意类型的数据都能进行排序

就比方下面的冒泡排序:

void bubble_sort(int arr[], int sz) {
	//趟数
	int i = 0;
	for (i = 0; i < sz - 1; i++) {
		//一趟内部的两两比较
		int j = 0;
		for (j = 0; j < sz - i - 1; j++) {
			if (arr[j] > arr[j + 1]) {
				int tmp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = tmp;
			}
		}
	}
}

这个程序排序整型数据是没问题的,但是能排序字符数组吗?能排序字符串吗?能排序浮点数吗?能排序结构体吗?

这个排序算法只能排序整型。

我们来看一下qsort函数的定义:

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

我们把这个代码划分一下:

void qsort (void* base, 
            size_t num, 
            size_t size,
            int (*compar)(const void*,const void*)//函数指针,传递函数的地址
           );

void* base:指向待排序数组的第一个元素的指针。

size_t num:base指向数组元素中元素的个数。

size_t size:base指向的数组元素中一个元素的大小,单位是字节。

int (*compar)(const void*,const void*):函数指针,传递函数的地址

字符串的大小比较大小不能使用>>=<<===!=

应该使用strcmp函数。

比较两个结构体呢?

也不能用>>=<<===!=比吧?

qsort函数能够实现排序,是因为它很聪明。

既然不同元素代码的比较不同,那么就把他抽离出来。谁要调用这个qsort函数进行比较,那么谁就来提供比较函数。

这也就是为什么会有个函数指针的原因。

#include <stdio.h>
#include <stdlib.h>
/*
cmp_int函数对函数的返回值有要求
p1指向的元素比p2指向的元素小的时候,返回一个小于0的数字
p1指向的元素和p2指向的元素一样的时候,返回一个等于0的数字
p1指向的元素比p2指向的元素大的时候,返回一个大于0的数字
*/
int cmp_int(const void* p1, const void* p2) {
	if (*(int*)p1 > *(int*)p2) {// 将指针 p1 和 p2 强制转换为指向 int 的指针,然后通过解引用获取指针指向的整数值
		return 1;
	 }
	else if (*(int*)p1 < *(int*)p2) {
		return -1;
	}
	else {
		return 0;
	}
}
//当然上面也可以直接返回:
//return *(int*)p1 - *(int*)p2;

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

void test1() {
	int arr[] = { 3,1,7,9,4,2,6,5,8,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_int);
	print_arr(arr, sz);
}

int main() {
	test1();
	return 0;
}

打印:

0 1 2 3 4 5 6 7 8 9

2.2 使⽤qsort排序结构数据

我们先看一下打印结构体的操作:

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

/*结构体成员访问操作符:
. :结构体变量.成员名
->:结构体指针->成员名
*/
int main() {
	struct Stu s = { "zhangsan",20 };
	printf("%s %d\n", s.name, s.age);

	struct Stu* ps = &s;//struct Stu*是结构体指针类型,指针名是ps
	printf("%s %d\n", (*ps).name, (*ps).age);
	printf("%s %d\n", ps->name, ps->age);

	return 0;
}

打印:

zhangsan 20
zhangsan 20
zhangsan 20

下面的代码中有关于strcmp函数的使用,如果不记得的可以看之前的这篇博客:

【C语言】strcmp函数讲解

通过qsort函数,按照名字比较结构体数据大小:

#include <string.h>
#include <stdlib.h>

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

//按照名字比较两个结构体数据
//名字是字符串,字符串比较是用strcmp函数的
int cmp_stu_by_name(const void* p1, const void* p2) {
	return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}

//测试qsort函数来排序结构体数据
void test2() {
	struct Stu arr[] = { {"zhangsan",20},{"list",35},{"wangwu",18} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
}
int main() {
	test2();
	return 0;
}

通过qsort函数,按照年龄比较结构体数据大小:

#include <string.h>
#include <stdlib.h>

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;
}//想逆序的话就这么写:
//return ((struct Stu*)p2)->age - ((struct Stu*)p1)->age;
//其实就是把p1和p2换个位置。

void test3() {
	struct Stu arr[] = { {"zhangsan",20},{"list",35},{"wangwu",18} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	qsort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
}

int main() {
	test3();
	return 0;
}

3.qsort函数的模拟实现

刚刚我们一开始用的是冒泡排序,那么我们能不能把冒泡排序改造一下呢?改造成和qsort函数一样,可以接受任意类型的数据呢?

在这里插入图片描述

这里(char*)base+4就是加了4个字节。也就是一个数组位。因为这里是整型数组,一位4字节。

如果不是整形数组,那就是加了width个字节。

从9到8是:(char*)base+0(char*)base+4

从8到7是:(char*)base+4(char*)base+8

中间差的就是位数乘上width

(改版)冒泡排序测试整型:

#include <stdlib.h>

int cmp_int(const void* p1, const void* p2) {
	if (*(int*)p1 > *(int*)p2) {// 将指针 p1 和 p2 强制转换为指向 int 的指针,然后通过解引用获取指针指向的整数值
		return 1;
	}
	else if (*(int*)p1 < *(int*)p2) {
		return -1;
	}
	else {
		return 0;
	}
}

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

void Swap(char* buf1, char* buf2, size_t width) {
	int i = 0;
	char tmp = 0;
	for (i = 0; i < width; i++) {
		tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;

		buf1++;
		buf2++;
	}
}

void bubble_sort(void* base, size_t sz, size_t width, int (*compar)(const void* p1, const void* p2)) {
	//趟数
	int i = 0;
	for (i = 0; i < sz - 1; i++) {
		//一趟内部的两两比较
		int j = 0;
		for (j = 0; j < sz - i - 1; j++) {
			//比较两个元素
			if (compar((char*)base + j * width, (char*)base + (j + 1) * width) > 0) {
				//交换两个元素
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

void test4() {
	int arr[] = { 3,1,7,9,4,2,6,5,8,0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
	print_arr(arr, sz);
}

int main() {
	test4();
	return 0;
}

打印:

0 1 2 3 4 5 6 7 8 9

(改版)冒泡排序测试结构体:

比较名字

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

//按照名字比较两个结构体数据
//名字是字符串,字符串比较是用strcmp函数的
int cmp_stu_by_name(const void* p1, const void* p2) {
	return strcmp(((struct Stu*)p1)->name, ((struct Stu*)p2)->name);
}

void Swap(char* buf1, char* buf2, size_t width) {
	int i = 0;
	char tmp = 0;
	for (i = 0; i < width; i++) {
		tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;

		buf1++;
		buf2++;
	}
}

void bubble_sort(void* base, size_t sz, size_t width, int (*compar)(const void* p1, const void* p2)) {
	//趟数
	int i = 0;
	for (i = 0; i < sz - 1; i++) {
		//一趟内部的两两比较
		int j = 0;
		for (j = 0; j < sz - i - 1; j++) {
			//比较两个元素
			if (compar((char*)base + j * width, (char*)base + (j + 1) * width) > 0) {
				//交换两个元素
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

//测试qsort函数来排序结构体数据
void test5() {
	struct Stu arr[] = { {"zhangsan",20},{"list",35},{"wangwu",18} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_name);
}

int main() {
	test5();
	return 0;
}

比较年龄

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;
}//想逆序的话就这么写:
//return ((struct Stu*)p2)->age - ((struct Stu*)p1)->age;
//其实就是把p1和p2换个位置。

void Swap(char* buf1, char* buf2, size_t width) {
	int i = 0;
	char tmp = 0;
	for (i = 0; i < width; i++) {
		tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;

		buf1++;
		buf2++;
	}
}

void bubble_sort(void* base, size_t sz, size_t width, int (*compar)(const void* p1, const void* p2)) {
	//趟数
	int i = 0;
	for (i = 0; i < sz - 1; i++) {
		//一趟内部的两两比较
		int j = 0;
		for (j = 0; j < sz - i - 1; j++) {
			//比较两个元素
			if (compar((char*)base + j * width, (char*)base + (j + 1) * width) > 0) {
				//交换两个元素
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}

void test6() {
	struct Stu arr[] = { {"zhangsan",20},{"list",35},{"wangwu",18} };
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_stu_by_age);
}

int main() {
	test6();
	return 0;
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Prime1 - 信息收集和分析能力的试炼

主机发现 nmap扫描与分析 端口22、80 详细扫描&#xff1b;linux、ubuntu、 udp扫描 端口都是关闭的 脚本扫描 web渗透 打开只有一张图片&#xff1b;源码有图片和一个alt&#xff1a;hnp security不知道有啥用&#xff0c;先记录下来吧 继续web渗透思路走吧&#xff0c;目录…

线性代数|机器学习-P3乘法和因式分解矩阵

文章目录 1. 矩阵分解2. S Q Λ Q T SQ\Lambda Q^T SQΛQT3. A U Σ V T AU\Sigma V^T AUΣVT4. A LU 分解5. 矩阵的四个子空间 1. 矩阵分解 目前我们有很多重要的矩阵分解&#xff0c;每个分解对应于多个前提条件&#xff0c;分解方法&#xff0c;分解后的形状会中如下&…

如何跨渠道分析销售数据 - 6年制造业销售经验小结

如何跨渠道分析销售数据 - 6年制造业销售经验小结&#xff08;1&#xff09; 【前言】 在我过去6年销售工作生涯中&#xff0c;从第一年成为公司销冠后&#xff0c;我当时的确自满的一段时间&#xff0c;认为自己很了不起。但是第一年的销售业绩并没有拿到提成&#xff0c;最…

“一键”掌控数据库特权,DpEasy 新版本即将启航

去年11月&#xff0c;我们在 BinTools 社区推出了一款新产品——DpEasy。在我们最初设计这款产品的时候&#xff0c;我们给出的定位是「数据库安全风险扫描工具」&#xff0c;目标是提供一种简单、安全且高效的方式来管理数据库账号密码以及分析数据库账号的使用情况&#xff0…

Python开发与应用实验1 | 开发环境安装配置

*本文来自博主对专业课 Python开发与应用 实验部分的整理与解析。 *一些题目可能会增加了拓展部分&#xff08;⭐&#xff09;。拓展部分不是实验报告中原有的内容&#xff0c;而是博主本人的补充&#xff0c;以便各位学习参考。 *实验环境为&#xff1a;Python 3.10 &#xf…

[AFCTF 2018]JPython

小祥为了保护自己的代码&#xff0c;修改了部分Python Bytecode指令集&#xff0c;并把这个指令集称之为JPython&#xff0c; JPython只能在他私人定制的环境上才能运行&#xff0c;其他人无法得到这个环境。 现在&#xff0c;小明为了获取小祥代码中的秘密&#xff0c;收集到了…

LangChain实战技巧之四:当模型(Model)不支持Tool/Function的解决办法

文心大模型两大主力模型已全面免费&#xff0c;可参考我之前发的文章 AI菜鸟向前飞 — 今日三则AI相关新闻 但是&#xff0c;这些模型原生并不支持Tool/Function Call 如下所示&#xff1a; tool def greeting(name: str):向朋友致欢迎语return f"你好啊, {name}"…

xilinx ip自带XDC只读

检查生成的IP核再目录下显示的文件类型是不是.xcix 如果是的话&#xff0c;重新生成为.xci 再二次编辑即可 或者 将框柱的部分不选择&#xff0c;从新生成

在潮流时尚的绿地新都会,竟然藏了一家神奇的工作室

绿地新都会新开的国学文化工作室有点不一样&#xff01;拜师终南山汇通中西方文化融合东西方数术更适合中国宝宝体质的新天地 探索人生规律&#xff0c;改善家居环境&#xff0c;强化自身能量 查看人生剧本&#xff0c;观看图卡心理学TAROT 关于创始人妙霏老师 生活环境研究…

AWS 高防和阿里云高防深度对比

随着网络攻击的不断增加&#xff0c;企业对于网络安全的需求也越来越高。在这种情况下&#xff0c;高防护服务成为了企业网络安全的重要组成部分。AWS和阿里云作为全球领先的云计算服务提供商&#xff0c;都提供了高防护服务&#xff0c;但它们之间存在着一些差异。我们九河云一…

WebGL开发三维家装设计

使用WebGL开发三维家装设计软件是一项复杂而有趣的任务&#xff0c;涉及3D建模、渲染、用户交互等多个方面。以下是详细的开发步骤和技术要点。北京木奇移动技术有限公司&#xff0c;专业的软件外包开发公司&#xff0c;欢迎交流合作。 1. 需求分析 目标用户 家装设计师家装公…

二人订单共享结束制:终身受益的新模式

在当今快速发展的互联网时代&#xff0c;一个创新的商业模式总能引起广泛关注。其中&#xff0c;“二人订单共享结束制”以其独特的魅力&#xff0c;吸引了众多消费者和创业者的目光。这一模式不仅为消费者带来了实惠&#xff0c;更为创业者提供了一个全新的平台。 只需购买一…

机关——用钥匙开对应的门

代码展示 玩家背包代码&#xff08;挂载到玩家身上&#xff09; using System.Collections; using System.Collections.Generic; using UnityEngine; /// <summary> /// 玩家背包脚本&#xff0c;用来记录玩家道具 /// </summary> public class MyBag : MonoBeha…

2.8万字总结:金融核心系统数据库升级路径与场景实践

OceanBase CEO 杨冰 谈及数字化转型&#xff0c;如果说过去还只是头部金融机构带动效应下的“选择题”。那么现在&#xff0c;我相信数字化转型已经成为不论大、中、小型金融机构的“必答题”。 本文为OceanBase最新发布的《万字总结&#xff1a;金融核心系统数据库升级路径…

nssctf刷题总结

首先就是关于"\x00"截断问题&#xff0c;\x00被当做字符串的截止字符&#xff0c;这就很有趣了我们可以把\x00放在我们要发送数据的前面&#xff0c;经过\x00截断&#xff0c;后面的数据就不用读入了。。。。。。嘿嘿&#xff0c;好像听起来没什么用&#xff0c;确实…

CentOS7某天的samba服务搭建操作记录(还没成功)

#CentOS7 yum软件仓库阿里云 samba服务器配置失败 sensors成功了 (花了200元组装H61测试机&#xff0c;75元的主板只有一块能用&#xff0c;垃圾板但又不完全能用&#xff09; 2024.5月的某天记录如下&#xff1a; https://blog.csdn.net/dszgf5717/article/details/53732182 …

数据与结构——哈夫曼树

哈夫曼树的基本概念 哈夫曼树&#xff08;Huffman Tree&#xff09;是一种用于数据压缩的最优二叉树&#xff0c;广泛应用于哈夫曼编码中。其基本概念和构建方法如下&#xff1a; 基本概念 二叉树&#xff1a;哈夫曼树是一种特殊的二叉树。权重&#xff1a;每个节点都有一个…

【vue3 + Echarts 】中国地图省市区下钻,并返回上级

实现效果如果&#xff1a; echarts版本&#xff1a; 地图数据来源&#xff1a;阿里云数据可视化平台 代码 <template><div class"mapWrapper"><a-button type"primary" click"goBack">返回上级</a-button><div…

python编程:实现对数据库中图片文件的查看及比对

当谈到图像查看和管理时,我们往往会使用一些工具软件,比如Windows自带的照片查看器或者第三方工具。那如果你想要一个更加强大和定制化的图像查看器呢?这时候就需要自己动手写一个程序了。 C:\pythoncode\new\ShowSqliteImage.py 这里我们将介绍一个使用Python和wxPython编写…

赛轮集团受邀出席2024国际新能源智能网联汽车创新生态大会

赛轮集团受邀出席2024国际新能源智能网联汽车创新生态大会 5月22日-24日&#xff0c;以“汽车供应链的创新与重构”为主题的2024国际新能源智能网联汽车创新生态大会&#xff08;以下简称CIEV2024&#xff09;在温州瑞安隆重召开。会议期间&#xff0c;CIEV2024高端对话成功召…