浅学指针(4)函数指针数组和qsort的使用

系列文章目录

文章目录

  • 系列文章目录
  • 前言
  • 1.函数指针数组的⽤途
    • 作用:可以让代码更简洁,逻辑更清晰
  • 2. 回调函数
    • 回调函数就是⼀个通过函数指针调⽤的函数
  • 3 . qsort函数
    • qsort函数可以排序所有数据类型
    • 解释如图:![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/a3eca975d2f1467db785660acf7e0209.png) 比较函数是用函数指针接收,内部实现后面我还会讲
    • 3. 1使⽤qsort排序结构体数据
  • 5 ..qsort函数的模拟实现
    • 补充:qsort可以排所有的数据类型,下面写的代码是qsort内部实现


前言

掌握函数指针数组的使用,qsort函数的实现。

1.函数指针数组的⽤途

作用:可以让代码更简洁,逻辑更清晰

计算机的实现:
简单的加减法运算
代码1

#include <stdio.h>
int add(int a, int b)//加法
{
 	return a + b;
}
int sub(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(" 0:exit 				 \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;
 	default:
 		printf("选择错误\n");
 		break;
 	}
 } while (input);
 return 0;
}

在这里插入图片描述
这个时候就可以用函数指针数组了,
改造:
代码2

#include <stdio.h>
int add(int a, int b)
{
 	return a + b;
}
int sub(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 x, y;
 	int input = 1;
 	int ret = 0;
 	int(*p[3])(int x, int y) = { 0, add, sub }; //转移表
 do
 {
  	printf("*************************\n");
 	printf(" 1:add 			   2:sub \n");
 	printf(" 0:exit 				 \n");
 	printf("*************************\n");
 	printf("请选择:");
 	scanf("%d", &input);
	if ((input <= 4 && input >= 1)){
 		printf( "输⼊操作数:" );
 		scanf( "%d %d", &x, &y);
 		ret = (*p[input])(x, y);
 		printf( "ret = %d\n", ret);
 	}
 	else if(input == 0)
 	{
 		printf("退出计算器\n");
 	}
 	else
 	{
 		printf( "输⼊有误\n" ); 
 	}
  	return 0;
}

看这样子是不是很简洁,那么是怎么调用的呢?

int(*p[3])(int x, int y) = { 0, add, sub };

如图:
在这里插入图片描述

2. 回调函数

回调函数就是⼀个通过函数指针调⽤的函数

如果你把函数的指针(地址)作为参数传递给另⼀个函数,当这个指针被⽤来调⽤其所指向的函数时,被调⽤的函数就是回调函数。
回调函数不是由该函数的实现⽅直接调⽤,⽽是在特定的事件或条件发⽣时由另外的⼀⽅调⽤的,⽤于对该事件或条件进⾏响应。上面代码1中我们写的计算机的实现的代码中,红⾊框中的代码是重复出现的,其中虽然执⾏计算的逻辑是区别的,但是输⼊输出操作是冗余的,有没有办法,简化⼀些呢?
因为红⾊框中的代码,只有调⽤函数的逻辑是有差异的,我们可以把调⽤的函数的地址以参数的形式传递过去,使⽤函数指针接收,函数指针指向什么函数就调⽤什么数,这⾥其实使⽤的就是回调函数的功能。

3 . qsort函数

qsort函数可以排序所有数据类型

传参必要参数:
在这里插入图片描述
那她是怎么实现的呢?
代码3:

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

解释如图:在这里插入图片描述
比较函数是用函数指针接收,内部实现后面我还会讲

3. 1使⽤qsort排序结构体数据

可以按名字,也可以按年龄
代码4:

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

其中代码解释,如图:
在这里插入图片描述

5 …qsort函数的模拟实现

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

补充:qsort可以排所有的数据类型,下面写的代码是qsort内部实现

注意:这⾥第⼀次使⽤ void* 的指针,讲解 void* 的作⽤。

#include<stdio.h>
int int_cmp(const void * p1, const void * p2)//比较函数跟qsort函数的比较函数一样
{
 	return (*( int *)p1 - *(int *) p2);
}
void _swap(void *p1, void * p2, int size)
{
 	int i = 0;
 	for (i = 0; i< size; i++)//因为不知道数据类型(void)所以两个元素选择一个一个字节交换
 	{
 		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)//cmp函数返回值是int,判断>0,如果成立,执行语句
 		{
 			_swap(( char *)base + j*size, (char *)base + (j + 1)*size, 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;
}

解析:在上面代码注释里,还有if语句代码的解释,如图:
在这里插入图片描述
好了,这就是今天所有的内容啦!宝子们都看到这里了,点一个赞,谢谢,下期再见.

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

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

相关文章

【高效开发工具系列】Hutool DateUtil工具类

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

Leetcode-二叉树oj题

1.二叉树的前序遍历 144. 二叉树的前序遍历https://leetcode.cn/problems/binary-tree-preorder-traversal/这个题目在遍历的基础上还要求返回数组&#xff0c;数组里面按前序存放二叉树节点的值。 既然要返回数组&#xff0c;就必然要malloc一块空间&#xff0c;那么我们需…

Spring简单的存储和读取

前言 前面讲了spring的创建&#xff0c;现在说说关于Bean和五大类注解 一、Bean是什么&#xff1f; 在 Java 语⾔中对象也叫做 Bean&#xff0c;所以后⾯咱们再遇到对象就以 Bean 著称。这篇文章还是以spring创建为主。 二、存储对象 2.1 俩种存储方式 需要在 spring-conf…

作用域和作用域链

前端面试大全JavaScript作用域和作用域链 &#x1f31f;经典真题 &#x1f31f;作用域&#xff08;Scope&#xff09; 什么是作用域 全局作用域和函数作用域 块级作用域 &#x1f31f;作用域链 什么是自由变量 什么是作用域链 关于自由变量的取值 &#x1f31f;作用域…

初识Linux:权限

目录 提示&#xff1a;以下指令均在Xshell 7 中进行 Linux 的权限 内核&#xff1a; 查看操作系统版本 查看cpu信息 查看内存信息 外部程序&#xff1a; 用户&#xff1a; 普通用户变为超级用户&#xff1a; su 和 su-的区别&#xff1a; root用户变成普通用户&#…

【matlab程序】画海洋流场

【matlab程序】画海洋流场 clear;clc; file ( ‘0227.nc’); latncread(file,‘latitude’); lonncread(file,‘longitude’); uncread(file,‘water_u’); vncread(file,‘water_v’); [x,y]meshgrid(lon,lat); xx’; yy’; interval4; figure (1) set(gcf,‘color’,[1 1 1…

【linux】基本指令(上篇)

1.快速认识5~6个指令 pwd指令 ls指令 touch指令 cd指令 clear指令 touch指令 详细讲解 首先有一个问题就是当我们创建一个文件&#xff0c;但是没有往里面写内容&#xff0c;那么磁盘上会有该文件吗&#xff1f; 磁盘上会保存&#xff0c;因为创建好的文件&#xff0c;没有…

【古月居《ros入门21讲》学习笔记】05_ROS是什么及其核心概念

目录 说明 1. ROS发展史 ROS版本演变 2. ROS是什么 ROS中的通信机制 ROS中的开发工具 ROS中的应用功能 ROS中的生态系统 3. ROS核心概念 节点与节点管理器 通信方式1&#xff1a;话题 通信方式2&#xff1a;服务 话题与服务的区别 参数 文件系统 说明 1. 本系列…

学习笔记7——数据库基础知识以及mysql的查询语句

学习笔记系列开头惯例发布一些寻亲消息 链接&#xff1a;https://baobeihuijia.com/bbhj/contents/3/199913.html 数据库 三个概念区分 DB&#xff1a;数据库&#xff0c;存储数据的仓库&#xff0c;有组织的数据容器DBMS:数据库管理系统SQL&#xff1a;几乎所有的DBMS都支持…

从PDF和图像中提取文本,以供大型语言模型使用

想法 大型语言模型已经席卷了互联网&#xff0c;导致更多的人没有认真关注使用这些模型最重要的部分&#xff1a;高质量的数据&#xff01;本文旨在提供一些有效从任何类型文档中提取文本的技术。 Python库 本文专注于Pytesseract、easyOCR、PyPDF2和LangChain库。实验数据是一…

jQuery的使用

目录 jquery对象&#xff1a; jquery作为一般函数调用参数: jquery事件机制 jquery dom操作 jquery对象&#xff1a; <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" cont…

MySQL 教程 1.4

MySQL 连接 使用mysql二进制方式连接 您可以使用MySQL二进制方式进入到mysql命令提示符下来连接MySQL数据库。 实例 以下是从命令行中连接mysql服务器的简单实例&#xff1a; [roothost]# mysql -u root -p Enter password:****** 在登录成功后会出现 mysql> 命令提示窗…

Python全栈之基本数据类型详解

文章目录 1.注释2.输出3.变量4.命名规范5.变量的定义方式1.字符串类型2.数字类型3.List列表类型4.tuple 元组类型的定义5.Dict字典类型6.set集合类型7.数据类型转换8.自动类型转换9.强制类型转换关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品…

Reactor网络线程模型

目录 传统下网络服务模型 事件监听模型 NIO核心概念 单线程Reactor模式 多线程Reactor模式 Kafka 的网络设计 主要概念 类比思维理解 参考文章 传统下网络服务模型 线程太多无法处理大规模请求 事件监听模型 NIO核心概念 nio是实现reactor模式的底层API代码 单…

【SparkSQL】SparkSQL函数定义(重点:定义UDF函数、使用窗口函数)

【大家好&#xff0c;我是爱干饭的猿&#xff0c;本文重点介绍SparkSQL 定义UDF函数、SparkSQL 使用窗口函数。 后续会继续分享其他重要知识点总结&#xff0c;如果喜欢这篇文章&#xff0c;点个赞&#x1f44d;&#xff0c;关注一下吧】 上一篇文章&#xff1a;《【SparkSQL…

C++相关闲碎记录(2)

1、误用shared_ptr int* p new int; shared_ptr<int> sp1(p); shared_ptr<int> sp2(p); //error // 通过原始指针两次创建shared_ptr是错误的shared_ptr<int> sp1(new int); shared_ptr<int> sp2(sp1); //ok 如果对C相关闲碎记录(1)中记录的shar…

【前缀和]LeetCode1862:向下取整数对和

本文涉及的基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 作者推荐 动态规划LeetCode2552&#xff1a;优化了6版的1324模式 题目 给你一个整数数组 nums &#xff0c;请你返回所有下标对 0 < i, j < nums.length 的 …

一文带你了解网络安全简史

网络安全简史 1. 上古时代1.1 计算机病毒的理论原型1.2 早期计算机病毒1.3 主要特点 2. 黑客时代2.1 计算机病毒的大流行2.2 知名计算机病毒2.3 主要特点 3. 黑产时代3.1 网络威胁持续升级3.2 代表性事件3.3 主要特点 4 高级威胁时代4.1 高级威胁时代到来4.2 著名的APT组织4.3 …

Python之Requests模块简介与安装

Requests模块简介 在python的标准库中&#xff0c;虽然提供了urllib,utllib2,httplib&#xff0c;但是做接口测试&#xff0c;requests使用更加方便快捷&#xff0c;正如官方说的&#xff0c;“让HTTP服务人类”。 Requests是用python语言基于urllib编写的&#xff0c;采用的是…

利用异或、取反、自增bypass_webshell_waf

目录 引言 利用异或 介绍 eval与assert 蚁剑连接 进阶题目 利用取反 利用自增 引言 有这样一个waf用于防御我们上传的文件&#xff1a; function fun($var): bool{$blacklist ["\$_", "eval","copy" ,"assert","usort…