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

news2024/12/30 21:02:12

文章目录

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

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

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

相关文章

如何为律师制作专业的商务名片?含电子名片二维码

律师关注细节&#xff0c;律师名片也不例外。它们不仅仅是身份的象征&#xff0c;更是律师专业形象的代表&#xff0c;传递专业知识和信任。今天就来和我们一起来看看制作律师商务名片的注意事项&#xff0c;以及如何制作商务名片上的电子名片二维码&#xff1f; 一、名片的主…

kafka学习笔记 @by_TWJ

目录 1. 消息重复消费怎么解决1.1. 确保相同的消息不会被重复发送(消费幂等性)1.2. 消息去重1.3. 消息重试机制1.4. kafka怎么保证消息的顺序性1.4.1. 利用分区的特征&#xff1a;1.4.2. 解决办法&#xff1a;1.4.3. 分区分配策略1.4.3.1. RangeAssignor &#xff08;每组(Topi…

Windows下安装和配置Redis

目录 1、下载redis压缩包 2、解压redis文件 3、启动redis临时服务 4、打开Redis客户端进行连接 5、使用一些基础操作来测试 5.1、输入ping命令来检测redis服务器与redis客户端的连通性 5.2、使用set和get命令测试redis数据库进行数据存储和获取 5.3、在命令中通过shut…

vs中C++项目中没有QT(.pro)文件怎么生成翻译ts文件

目录 使用 CMake 生成翻译文件 1.创建 CMakeLists.txt 文件 2.添加翻译生成规则 3.运行 CMake 4.生成翻译文件 使用命令行工具生成翻译文件 1.运行 lupdate 2.编辑 .ts 文件 3.运行 lrelease 网络上说的情况都是一个qt程序在VS中打开&#xff0c;拥有.pro文件的情况&a…

解决远程服务器连接报错

最近使用服务器进行数据库连接和使用的时候出现了一个报错&#xff1a; Error response from daemon: Conflict. The container name “/mysql” is already in use by container “1bd3733123219372ea7c9377913da661bb621156d518b0306df93cdcceabb8c4”. You have to remove …

什么是WEB应用防火墙,云服务器有带吗

伴随着Web软件、SaaS应用及API交互的使用普及&#xff0c;网络安全威胁也随之而来。网络攻击者一直不断改进他们的方法&#xff0c;使用自动爬虫程序、僵尸网络和漏洞扫描器来发动多媒介攻击&#xff0c;试图瘫痪应用。而WAF防火墙可以帮助保护Web应用程序免受这些攻击&#xf…

10.爬虫---XPath插件安装并解析爬取数据

10.XPath插件安装并解析爬取数据 1.XPath简介2.XPath helper安装3.XPath 常用规则4.实例引入4.1 //匹配所有节点4.2 / 或 // 匹配子节点或子孙节点4.3 ..或 parent::匹配父节点4.4 匹配属性4.5 text()文本获取4.6 属性获取4.7 属性多值匹配 1.XPath简介 XPath是一门在XML文档中…

让你工作效率飞起的五款软件

&#x1f31f; No.1&#xff1a;亿可达 作为一款自动化工具&#xff0c;亿可达被誉为国内版的免费Zaiper。它允许用户无需编程知识即可将不同软件连接起来&#xff0c;构建自动化的工作流程。其界面设计清新且直观&#xff0c;描述语言简洁易懂&#xff0c;使得用户可以轻松上…

一个可以自动生成随机区组试验的excel VBA小程序

在作物品种区域试验时&#xff0c;通常会采用随机区组试验设计&#xff0c;特制作了一个可以自动生成随机区组试验的小程序。excel参数界面如下&#xff1a; 参数含义如下&#xff1a; 1、生成新表的名称&#xff1a;程序将新建表格&#xff0c;用于生成随机区组试验。若此处为…

探索通信技术的未来:2024中国通信技术和智能装备产业博览会

探索通信技术的未来&#xff1a;2024通信技术产业专场 随着信息技术的飞速发展&#xff0c;通信技术已成为现代社会不可或缺的基础设施。2024年10月11日至13日&#xff0c;青岛将迎来一场通信技术的盛会——2024中国军民两用智能装备与通信技术产业博览会。本次博览会不仅将展…

调试线上资源文件失效问题

之前的老项目&#xff0c;突然报红&#xff0c;为了定位问题&#xff0c;使用注入和文件替换的方式进行问题定位&#xff01; 1.使用注入 但是刷新后就没有了&#xff0c;不是特别好用&#xff01; const jqScript document.createElement(script); jqScript.src https://…

视频推广短信:新时代的营销利器(视频短信XML接口示例)

随着移动互联网的普及&#xff0c;短信已经不再是简单的文字信息传递工具&#xff0c;而是逐渐演变为一种有效的推广手段。特别是当视频与短信结合时&#xff0c;它所带来的营销效率更是令人瞩目。 一、视频推广短信的特点 1.直观性&#xff1a;与传统的文字短信相比&#xf…

MySQL存储引擎的区别和比较

MyISAM存储引擎 MyISAM基于ISAM存储引擎&#xff0c;并对其进行扩展。它是在Web、数据仓储和其他应用环境下最常使用的存储引擎之一。MyISAM拥有较高的插入、查询速度&#xff0c;但不支持事务。 MyISAM主要特性有&#xff1a; 1、大文件&#xff08;达到63位文件长度&#x…

图片像素缩放,支持个性化自定义与精准比例调整,让图像处理更轻松便捷!

图片已经成为我们生活中不可或缺的一部分。无论是社交媒体的分享&#xff0c;还是工作文档的编辑&#xff0c;图片都扮演着至关重要的角色。然而&#xff0c;你是否曾经遇到过这样的问题&#xff1a;一张高清大图在上传时却受限于平台的大小要求&#xff0c;或者一张小图需要放…

PPT视频如何16倍速或者加速播放

有两种方式&#xff0c;一种是修改PPT本身&#xff0c;这种方式非常繁琐&#xff0c;不太推荐&#xff0c;还有一种就是修改视频本身&#xff0c;直接让视频是16倍速的视频即可。 如何让视频16倍速&#xff0c;我建议人生苦短&#xff0c;我用Python&#xff0c;几行代码&…

Kafka生产者消息异步发送并返回发送信息api编写教程

1.引入依赖&#xff08;pox.xml文件&#xff09; <dependencies> <dependency> <groupId>org.apache.kafka</groupId> <artifactId>kafka-clients</artifactId> <version>3.6.2</version> </dependency> </depende…

0基础学习区块链技术——推演猜想

大纲 去中心预防篡改付出代价方便存储 在《0基础学习区块链技术——入门》一文中&#xff0c;我们结合可视化工具&#xff0c;直观地感受了下区块的结构&#xff0c;以及链式的前后关系。 本文我们将抛弃之前的知识&#xff0c;从0开始思考和推演&#xff0c;区块链技术可能是如…

【必会面试题】快照读的原理

目录 前言知识点一个例子 前言 快照读&#xff08;Snapshot Read&#xff09;是数据库管理系统中一种特殊的读取机制&#xff0c;主要用于实现多版本并发控制&#xff08;MVCC, Multi-Version Concurrency Control&#xff09;策略&#xff0c;尤其是在MySQL的InnoDB存储引擎中…

hadoop疑难问题解决_NoClassDefFoundError: org/apache/hadoop/fs/adl/AdlFileSystem

1、问题描述 impala执行查询&#xff1a;select * from stmta_raw limit 10; 报错信息如下&#xff1a; Query: select * from sfmta_raw limit 10 Query submitted at: 2018-04-11 14:46:29 (Coordinator: http://mrj001:25000) ERROR: AnalysisException: Failed to load …

关于一些优化的知识

1、凸优化&#xff1a;一定可找到全局最优解 非凸优化&#xff1a;一般是局部最优解 2、无约束优化问题求解方法&#xff1a;梯度下降、拟牛顿法、高斯牛顿法、LM算法 3、 解释&#xff0c;就是右边的式子对应于就是当前这个xk这个点基础上朝着pk取走步长为a得到了对应的值&…