Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
社区首页 >专栏 >C语言进阶-回调函数

C语言进阶-回调函数

作者头像
用户9645905
发布于 2022-11-30 00:08:56
发布于 2022-11-30 00:08:56
96100
代码可运行
举报
文章被收录于专栏:Linux学习~Linux学习~
运行总次数:0
代码可运行

目录

前言

回调函数

回调型计算器

回调冒泡排序(模拟qsort库函数)

qsort函数原型

compar参数

代码演示

 冒泡排序(bubble_sort)


前言


  • 本文主要讲解
  • 回调函数的理解
  • 回调实现计算器
  • qsort各种功能的使用
  • 冒泡排序各种功能的实现

回调函数


  • 定义

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

  • 示例1:

回调型计算器

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#define _CRT_SECURE_NO_WARNINGS
#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;
}

int moveleft(int x, int y)
{
	return x << y;
}

int moveright(int x, int y)
{
	return x >> y;
}

int mici(int x, int y)
{
	if (y >= 2)
		return x * mici(x, y - 1);
	return x;
}

int xor(int x, int y)
{
	return x ^ y;
}
//写出相应功能的函数

void menu()
{
	printf("************************\n");
	printf("***1.add        2.sub***\n");
	printf("***3.mul        4.div***\n");
	printf("*5.moveleft 6.moveright*\n");
	printf("***7.xor       8.mici***\n");
	printf("******** 0.exit ********\n");
	printf("************************\n");
}

void cola(int (*p)(int, int))//回调函数 形参为函数指针,接受函数地址
{
	int x, y;
	printf("请输入两个操作数:\n");
	scanf("%d %d", &x, &y);
	int ret = p(x, y);//利用函数指针,即函数地址来调用相应的函数
	printf("得到结果为:%d\n", ret);
}

int main()//计算器逻辑模拟
{
	int intput = 0;
	do {
		menu();
		printf("请选择:\n");
		scanf("%d", &intput);
		switch (intput)
		{
		case 0:
			printf("退出成功!\n");
			break;
		case 1:
			cola(add);//传入的函数降维成函数地址
			break;
		case 2:
			cola(sub);
			break;
		case 3:
			cola(mul);
			break;
		case 4:
			cola(div);
			break;
		case 5:
			cola(moveleft);
			break;
		case 6:
			cola(moveright);
			break;
		case 7:
			cola(xor);
			break;
		case 8:
			cola(mici);
			break;
		default:
			printf("输入错误!\n");
			break;
		}
	} while (intput);
	return 0;
}
  • 示例2:

回调冒泡排序(模拟qsort库函数)

  • 首先演示一下qsort函数的使用

qsort函数原型

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
void qsort(
    void *base,
    size_t nmemb,
    size_t size,
    int (*compar)(const void *, const void *)
    );

  •   头文件:<stdlib.h>
  •   函数功能:qsort()函数的功能是对数组进行排序,数组有nmemb个元素,每个元素大小为size
  •   参数base : base指向数组的起始地址,通常该位置传入的是一个数组名
  •   参数nmemb :nmemb表示该数组的元素个数
  •   参数size :size表示该数组中每个元素的大小(字节数)
  •   参数(*compar)(const void *, const void *):此为指向比较函数的函数指针
  •   函数返回值:无

compar参数

定义:实现比较功能的函数 注意:两个形参是const void *型(便于接收不同指针类型参数) 内部需将const void *型转换成实际类型(访问元素对应的空间大小,空类型指针无法反问)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int compar(const void *p1, const void *p2)
{
}

  •   如果compar返回值小于0(< 0),那么p1所指向元素会被排在p2所指向元素的前面
  •   如果compar返回值等于0(= 0),那么p1所指向元素与p2所指向元素的顺序不确定
  •   如果compar返回值大于0(> 0),那么p1所指向元素会被排在p2所指向元素的后面
  • 方法一
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 int compare (const void * a, const void * b)
 {
   if ( *(MyType*)a <  *(MyType*)b ) return -1;
   if ( *(MyType*)a == *(MyType*)b ) return 0;
   if ( *(MyType*)a >  *(MyType*)b ) return 1;
 }

注意:MyType是换成实际数组元素的类型

  • 方法二:

以实际元素是int为例

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
 int compare (const void * a, const void * b)
 {
     return ( *(int*)a - *(int*)b );
 }

注意:如果变量 a 指向一个较小的负整型数,b指向一个较大的正整型数,(*(int*)a - *(int*)b) 表达式会计算出一个正数,因此,比较int类型元素的大小可以使用大于、小于运算符来比较

代码演示

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<stdio.h>
#include<stdlib.h>//qasort函数头文件
#include<string.h>//strcmp函数头文件

struct stu//构建结构体,结构体同样是一种类型
{                //注意结构体类型的作用域,放在前面,后面才能使用结构体
	char name[9];
	int age;
};

int cmp_int(const void* e1, const void* e2)//要实现多功能qsort,所以传入的地址类型会有多种形式
{                                          //而void*空指针类型可以来接收不同的类型,便于保持参数一致性,构成回调函数的特点,形参和返回类型一致
	return *(int*)e1 - *(int*)e2;//知道该使用什么类型,就将其先强制转成对应类型(访问空间大小与指针类型有关),再解引用得到空间内容        
}//e1 - e2为升序,e2-e1为降序

int cmp_char(const void* e1, const void* e2)
{
	return *(char*)e1 - *(char*)e2;//字符类型直接比较,比较的是对应的ASCII码值
}

int cmp_double(const void* e1, const void* e2)
{
	return (int)(*(double*)e1 - *(double*)e2);
}

int cmp_stu_name(const void* e1, const void* e2)
{
	return strcmp(((struct stu*)e1)->name, ((struct stu*)e2)->name);//name是字符串,比较需要使用strcmp函数
}//结构体指针->成员 这样访问便捷

int cmp_stu_age(const void* e1, const void* e2)
{
	return ((struct stu*)e1)->age - ((struct stu*)e2)->age;//age为整型,直接比较
}

int main()
{
	char ch[] = { 'e','g','a','f','p','b' };
	int arr1[] = { 6,4,5,9,1,2,4,6,3 };
	double arr2[] = { 5.00,4.00,9.00,3.00,7.00 };
	struct stu s[] = { {"zhangsan",18},{"lisi",20},{"wangwu",22} };
	qsort(ch, sizeof(ch) / sizeof(ch[0]), sizeof(ch[0]), cmp_char);
	for (int i = 0; i < sizeof(ch) / sizeof(ch[0]); i++)
	{
		printf("%c ", ch[i]);
	}printf("\n");

	qsort(arr1, sizeof(arr1) / sizeof(arr1[0]), sizeof(arr1[0]), cmp_int);//最后的形参是函数,传入的是函数地址,qsort也相当于是一个回调函数
	for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
	{
		printf("%d ", arr1[i]);
	}printf("\n");

	qsort(arr2, sizeof(arr2) / sizeof(arr2[0]), sizeof(arr2[0]), cmp_double);
	for (int i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
	{
		printf("%lf ", arr2[i]);
	}printf("\n");

	qsort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), cmp_stu_name);
	for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++)
	{
		printf("%s ", s[i].name);
	}printf("\n");

	qsort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), cmp_stu_age);
	for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++)
	{
		printf("%d ", s[i].age);
	}printf("\n");
                //qsort函数相应比较的功能函数需要自己写
	return 0;
}
  • 输出结果:

 冒泡排序(bubble_sort)

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

struct stu
{
	char name[9] ;
	int age;
};

void sway(char* e1, char* e2,int size)//交换函数 使用char*指针指向一个字节,还需要宽度,才能将元素对应的空间完全交换,实现交换元素
{
	for (int k = 0; k < size; k++)
	{
		char temp = *e1;
		*e1 = *e2;//解引用实现内容交换
		*e2 = temp;
		e1++;//指向下一个字节空间地址
		e2++;
	}
}

void bubble_sort(void* base, int count, int size, int (*cmp)(const void*, const void*))//模拟qsort函数
{
	for (int i = 0; i < count - 1; i++)//趟数
	{
		for (int j = 0; j < count - 1 - i; j++)//一趟中相邻比较对数
		{
			if (cmp((char*)base + j * size, (char*)base + (j + 1) * size) > 0)//调用函数 升序
			{
				sway((char*)base + j * size, (char*)base + (j + 1) * size,size);//不符合就交换
			}
		}
	}
}

int cmp_int(const void* e1, const void* e2)
{
	return *(int*)e1 - *(int*)e2;
}

int cmp_char(const void* e1, const void* e2)
{
	return *(char*)e1 - *(char*)e2;
}

int cmp_double(const void* e1, const void* e2)
{
	return (int)(*(double*)e1 - *(double*)e2);
}

int cmp_stu_name(const void* e1, const void* e2)
{
	return strcmp(((struct stu*)e1)->name ,((struct stu*)e2)->name);
}

int cmp_stu_age(const void* e1, const void* e2)
{
	return ((struct stu*)e1)->age-((struct stu*)e2)->age;
}
//实现比较不同类型函数的功能

int main()
{
	char ch[] = {'e','g','a','f','p','b'};
	int arr1[] = { 6,4,5,9,1,2,4,6,3 };
	double arr2[] = { 5.00,4.00,9.00,3.00,7.00 };
	struct stu s[] = { {"zhangsan",18},{"lisi",20},{"wangwu",22} };
	bubble_sort(ch, sizeof(ch) / sizeof(ch[0]), sizeof(ch[0]), cmp_char);
	for (int i = 0; i < sizeof(ch) / sizeof(ch[0]); i++)//打印
	{
		printf("%c ", ch[i]);
	}
	printf("\n");

	bubble_sort(arr1, sizeof(arr1) / sizeof(arr1[0]), sizeof(arr1[0]), cmp_int);
	for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
	{
		printf("%d ", arr1[i]);
	}
	printf("\n");

	bubble_sort(arr2, sizeof(arr2) / sizeof(arr2[0]), sizeof(arr2[0]), cmp_double);
	for (int i = 0; i < sizeof(arr2) / sizeof(arr2[0]); i++)
	{
		printf("%lf ", arr2[i]);
	}
	printf("\n");

	bubble_sort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), cmp_stu_name);
	for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++)
	{
		printf("%s ", s[i].name);
	}
	printf("\n");

	bubble_sort(s, sizeof(s) / sizeof(s[0]), sizeof(s[0]), cmp_stu_age);
	for (int i = 0; i < sizeof(s) / sizeof(s[0]); i++)
	{
		printf("%d ", s[i].age);
	}
	printf("\n");

	return 0;
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2022-09-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
理解OAuth2.0认证
任何身份认证,本质上都是基于对请求方的不信任所产生的。同时,请求方是信任被请求方的,例如用户请求服务时,会信任服务方。
网络安全观
2021/02/25
7160
理解OAuth2.0认证
常识二Oauth2.0介绍及安全防范
OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。
码农戏码
2021/03/23
1.5K0
oauth2.0的学习与使用
栗子一: 小新现在想要使用一个“在线打印服务”来打印一些照片,同时小新的照片都存储在了“云网盘”上,按照传统的方式小新要怎么做呢?
向着百万年薪努力的小赵
2022/12/02
8710
理解OAuth2.0认证与客户端授权码模式详解
OAuth 协议为用户资源的授权提供了一个安全又简易的标准。与以往的授权方式不同之处是 OAuth的授权不会使第三方触及到用户的帐号信息(如用户名与密码),即第三方无需使用用户的用户名与密码就可以申请获得该用户资源的授权,因此 OAuth是安全的。OAuth 是 Open Authorization 的简写
BUG弄潮儿
2021/04/12
5.9K0
Oauth协议介绍与安全隐患
OAuth 是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。目前,OAuth 的最新版本为 2.0
信安之路
2018/08/08
1.4K0
Oauth协议介绍与安全隐患
OAuth2.0授权协议
通过用户授权,第三方服务访问用户存在其他服务上的资源,而不需用户将用户名密码直接传递的资源服务器的安全控制协议。
sucl
2019/09/05
6970
OAuth2.0授权协议
oauth2.0的授权流程详解
1、 在客户端web项目中构造一个oauth的客户端请求对象(OAuthClientRequest),在此对象中携带客户端信息(clientId、accessTokenUrl、response_type、redirectUrl),将此信息放入http请求中,重定向到服务端。此步骤对应上图1
Dream城堡
2018/09/10
3.7K0
oauth2.0的授权流程详解
OAuth 2.0 极简教程 (The OAuth 2.0 Authorization Framework)
OAuth(开放授权)是一个开放标准,允许用户授权第三方移动应用访问他们存储在另外的服务提供者上的信息,而不需要将用户名和密码提供给第三方移动应用或分享他们数据的所有内容,OAuth2.0 不兼容OAuth 1.0 。
一个会写诗的程序员
2020/10/29
3.1K0
OAuth 2.0 极简教程 (The OAuth 2.0 Authorization Framework)
OAuth2.0认证流程是如何实现的?
大家也许都有过这样的体验,我们登录一些不是特别常用的软件或网站的时候可以使用QQ、微信或者微博等账号进行授权登陆。例如我们登陆豆瓣网的时候,如果不想单独注册豆瓣网账号的话,就可以选择用微博或者微信账号进行授权登录。这样的场景还有很多,例如登录微博、头条等网站,也都可以选择QQ或者微信登录的方式。
用户5927304
2019/07/30
2.3K0
OAuth2.0认证流程是如何实现的?
OAuth2.0认证解析
OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。
FB客服
2020/11/16
4.5K0
OAuth2.0认证解析
OAuth2.0 认证
密码模式(Resource owner password credentials)流程
谢公子
2022/01/20
1.5K0
OAuth2.0 认证
OAuth 2.0 授权认证详解
点击上方“芋道源码”,选择“设为星标” 管她前浪,还是后浪? 能浪的浪,才是好浪! 每天 10:33 更新文章,每天掉亿点点头发... 源码精品专栏 原创 | Java 2021 超神之路,很肝~ 中文详细注释的开源项目 RPC 框架 Dubbo 源码解析 网络应用框架 Netty 源码解析 消息中间件 RocketMQ 源码解析 数据库中间件 Sharding-JDBC 和 MyCAT 源码解析 作业调度中间件 Elastic-Job 源码解析 分布式事务中间件 TCC-Transaction
芋道源码
2022/06/20
1.9K0
OAuth 2.0 授权认证详解
OAuth 2.0验证【面试+工作】
OAuth2.0验证【面试+工作】 OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。 本文对OAuth 2.0的设计思路和运行流程,
Java帮帮
2018/03/15
1.8K0
OAuth 2.0验证【面试+工作】
【全栈修炼】OAuth2 修炼宝典
> 开放授权(OAuth)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用。 —— 维基百科
pingan8787
2019/10/30
8200
OAuth2.0协议详解
更多可以访问:https://tools.ietf.org/html/rfc6749
山行AI
2019/06/28
1.5K0
OAuth2 认证
随着微服务的兴起,OAuth2也火了起来,由于其自身的优势,俨然已成为微服务API服务接口安全防护的首选。
BUG弄潮儿
2022/04/15
6160
OAuth2 认证
理解OAuth 2.0
  OAuth是一个关于授权(authorization)的开放网络标准,在全世界得到广泛应用,目前的版本是2.0版。   本文对OAuth 2.0的设计思路和运行流程,做一个简明通俗的解释,主要参考
用户1289394
2018/02/28
1.1K0
理解OAuth 2.0
从微信网页授权到OAuth 2.0
相信你使用某些APP需要做登录操作,那么,有可能会出现“微信登录”的按钮。点击该按钮,会跳转到如下页面:
娜姐
2020/09/22
2K0
从微信网页授权到OAuth 2.0
一张图搞定OAuth2.0
一项新的技术,无非就是了解它是什么,为什么,怎么用。至于为什么,本篇文章不做重点探讨,网上会有各种文章举各种什么丢钥匙、发船票的例子供你去阅读,个人认为还是有些哗众取宠,没有聊到本质。
DencyCheng
2018/11/05
8810
OAuth 2.0一键登录那些事
程序员对Gitee和Github都不陌生,Github可能是起源时间最早、用户范围最大的代码开源仓库,Gitee作为国产代码仓库的后起之秀,在用户模块也是做到了兼容Github的功能,如,在Gitee的登录界面可以通过Github授权的方式登录。这就是今天我要讲的OAuth 2.0,大家可以去Gitee体验一下UI交互流程,以更形象的理解OAuth 2.0的授权流程。
关忆北.
2022/06/27
5090
OAuth 2.0一键登录那些事
相关推荐
理解OAuth2.0认证
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
查看详情【社区公告】 技术创作特训营有奖征文
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验