当前位置: 首页 > news >正文

进阶C语言-指针的进阶(中)

在这里插入图片描述

指针的进阶

  • 📖5.函数指针
  • 📖6.函数指针数组
  • 📖7.指向函数指针数组的指针
  • 📖8.回调函数

📖5.函数指针

数组指针 - 指向数组的指针 - 存放的是数组的地址 - &数组名就是数组的地址。
函数指针 - 指向函数的指针 - 存放的是函数的地址 - &函数名就是函数的地址。

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{//&函数名就是函数的地址//函数名也是函数的地址printf("%p\n", &Add);printf("%p\n", Add);int (*pd1)(int, int) = &Add;//int (*pd2)(int, int) = Add;//pd2是函数指针变量int ret = (*pd1)(3, 5);printf("%d\n", ret);return 0;
}

在这里插入图片描述
🔭阅读下面这两段代码:

//代码1:
(*(void (*)())0)();
//void (*)()为函数指针类型
//下面这段代码是在调用0地址处的函数,这个函数没有参数,返回类型是void
//代码2:
void (*signal(int , void(*)(int)))(int);
//signal函数的参数有两个,第一个是int类型,第二个是函数指针类型,该类型是void(*)(int),该函数指向的类型是int,返回类型是void.signal函数也是函数指针类型,该类型是void(*)(int),该函数指向的类型是int,返回类型是void.

📖6.函数指针数组

🔭 指针数组:
字符指针数组 - 数组 - 存放的是字符指针
整型指针数组 - 数组 - 存放的是整型指针
那么函数指针数组 - 数组 - 存放的是函数指针 - 存放的是函数的地址。

#include <stdio.h>
int Add(int x, int y)
{return x + y;
}
int Sub(int x, int y)
{return x - y;
}
int main()
{int (*pf1)(int, int) = &Add;int (*pf2)(int, int) = &Sub;int (*pfArr[4])(int, int) = { &Add,&Sub };//pfArr是函数指针数组,是存放函数指针的数组 return 0;
}

🔎这里我们来模拟一下计算器的实现:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void menu()
{printf("******************************\n");printf("***   1.add        2.sub   ***\n");printf("***   3.mul        4.div   ***\n");printf("***   0.exit               ***\n");printf("******************************\n");
}
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 main()
{int input = 0;int x = 0;int y = 0;int ret = 0;do{menu();printf("请选择:>");scanf("%d", &input);switch (input){case 1:printf("请输入2个操作数:");scanf("%d %d", &x, &y);ret = Add(x, y);printf("ret = %d\n", ret);break;case 2:printf("请输入2个操作数:");scanf("%d %d", &x, &y);ret = Sub(x, y);printf("ret = %d\n", ret);break;case 3:printf("请输入2个操作数:");scanf("%d %d", &x, &y);ret = Mul(x, y);printf("ret = %d\n", ret);break;case 4:printf("请输入2个操作数:");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;
}

✅自测运行:
在这里插入图片描述
🎈程序不足:如果想要实现更多的功能||、&&、&、|、>>、<<等等,还得重复写一些步骤,就很冗余!
🏆这里,我们就可以利用函数指针数组的知识来优化它,函数指针数组的作用:转移表!

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void menu()
{printf("******************************\n");printf("***   1.add        2.sub   ***\n");printf("***   3.mul        4.div   ***\n");printf("***   0.exit               ***\n");printf("******************************\n");
}
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 main()
{int input = 0;int x = 0;int y = 0;int ret = 0;do{menu();printf("请选择:>");scanf("%d", &input);//函数指针数组-转移表int (*pfarr[])(int, int) = { NULL,Add,Sub,Mul,Div };if (0 == input){printf("退出程序!\n");}else if (input >= 1 && input <= 4){printf("请输入2个操作数:");scanf("%d%d", &x, &y);ret = pfarr[input](x, y);printf("ret = %d\n", ret);}else{printf("选择错误,请重新选择!\n");}} while (input);return 0;
}

在这里插入图片描述

📖7.指向函数指针数组的指针

指向函数指针数组的指针是一个指针,指针指向一个数组,数组的元素都是函数指针。

如何定义?

void test(const char* str)
{
printf("%s\n", str);
}
int main()
{
//函数指针pfun
void (*pfun)(const char*) = test;
//函数指针的数组pfunArr
void (*pfunArr[5])(const char* str);
pfunArr[0] = test;
//指向函数指针数组pfunArr的指针ppfunArr
void (*(*ppfunArr)[5])(const char*) = &pfunArr;
return 0;
}

📖8.回调函数

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

🔎这里,我们利用回调函数实现一下计算器:

#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
void menu()
{printf("******************************\n");printf("***   1.add        2.sub   ***\n");printf("***   3.mul        4.div   ***\n");printf("***   0.exit               ***\n");printf("******************************\n");
}
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;
}
void calc(int (*pf)(int, int))
{int x = 0;int y = 0;int ret = 0;printf("请输入2个操作数:");scanf("%d%d", &x, &y);ret = pf(x, y);printf("ret = %d\n", ret);
}
int main()
{int input = 0;do{menu();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;
}

✅自测运行:
在这里插入图片描述
🔎这里,我们演示一个qsort函数的实现:

qsort函数是一个库函数,底层使用的是快速排序的方式,对数据进行排序的这个函数可以直接使用,这个函数可以用来排序任意类型的数据。

🌞我们先一起回顾一下冒泡排序的内容:

//冒泡排序算法:
//给一组整型数据,然后使用冒泡排序算法,对数据进行升序排列
//冒泡排序的思想:两两相邻的元素进行比较
#include <stdio.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 - 1 - i; j++){if (arr[j] > arr[j + 1]){int tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}
void print_arr(int *arr,int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}printf("\n");
}
int main()
{int arr[] = { 9,8,7,6,5,4,3,2,1,0 };int sz = sizeof(arr) / sizeof(arr[0]);print_arr(arr, sz);//排序前bubble_sort(arr, sz);print_arr(arr, sz);//排序后return 0;
}

在这里插入图片描述

🎈缺陷:我们发现这个函数不够通用,只能排序整型类型!
📝关于qsort函数,我们可以先去cpluplus网站上面了解一下:

在这里插入图片描述

//1.排序整型数组,两个整型可以直接使用大于号比较。
//2.排序结构体数组,两个结构体数据可能不能直接使用大于号比较。
//不同类型的数据,比较出大小,方法是有差异的。
void qsort (void* base//待排序数组的第一个元素的地址
,           size_t num//待排序数组的元素个数
,           size_t size//待排序数组中一个元素的大小
,           int (*compar)(const void* e1,const void* e2));//函数指针compar指向了一个函数,这个函数是用来比较两个元素的
//e1和e2中存放的是需要比较的两个元素的地址

🔭关于void*类型的指针:

  1. void*类型的指针 - 不能进行解引用操作符,也不能进行±整数的操作
  2. void*类型的指针是用来存放任意类型数据的地址
  3. void*无具体类型的指针
#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 };//char *arr[] = {"aaaa","dddd","cccc","bbbb"};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;
}

好啦,关于进阶指针(中)的知识点到这里就结束啦,后期会继续更新C语言的相关知识,欢迎大家持续关注、点赞和评论!❤️❤️❤️

相关文章:

进阶C语言-指针的进阶(中)

指针的进阶 &#x1f4d6;5.函数指针&#x1f4d6;6.函数指针数组&#x1f4d6;7.指向函数指针数组的指针&#x1f4d6;8.回调函数 &#x1f4d6;5.函数指针 数组指针 - 指向数组的指针 - 存放的是数组的地址 - &数组名就是数组的地址。 函数指针 - 指向函数的指针 - 存放的…...

保姆级-微信小程序开发教程

一&#xff0c;注册微信小程序 如果你还没有微信公众平台的账号&#xff0c;请先进入微信公众平台首页&#xff0c;点击 “立即注册” 按钮进行注册。注册的账号类型可以是订阅号、服务号、小程序以及企业微信&#xff0c;我们选择 “小程序” 即可。 接着填写账号信息&#x…...

数据库-DQL

DQL&#xff1a;用来查询数据库表中的记录 关键字&#xff1a;SELECT 语法&#xff1a; select&#xff1a;字段列表 from&#xff1a;表名列表 where&#xff1a;条件列表 group by&#xff1a;分组列表 having&#xff1a;分组后条件列表 order by&#xff1a;排序字段列表…...

19 螺旋矩阵

螺旋矩阵 题解1 循环&#xff08;4个标志——根据顺时针&#xff09;题解2 方向 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 提示&#xff1a; - m matrix.length - n matrix[i].length - 1 < m, n <…...

数据结构与算法:概述

目录 算法 评价标准 时间的复杂度 概念 推导原则 举例 空间的复杂度 定义 情形 运用场景 数据结构 组成方式 算法 在数学领域&#xff0c;算法是解决某一类问题的公式和思想&#xff1b; 计算机科学领域&#xff0c;是指一系列程序指令&#xff0c;用于解决特定的…...

顺序表详解

&#x1f493; 博客主页&#xff1a;江池俊的博客⏩ 收录专栏&#xff1a;数据结构探索&#x1f449;专栏推荐&#xff1a;✅C语言初阶之路 ✅C语言进阶之路&#x1f4bb;代码仓库&#xff1a;江池俊的代码仓库&#x1f525;编译环境&#xff1a;Visual Studio 2022&#x1f38…...

基于RabbitMQ的模拟消息队列之六——网络通信设计

自定义基于TCP的应用层通信协议。实现客户端对服务器的远程调用 编写服务器及客户端代码 文章目录 基于TCP的自定义应用层协议一、请求1.请求格式2.创建Request类 二、响应1.响应格式2.创建Response类 三、客户端-服务器交互四、type五、请求payload1.BasicAruguments(方法公共…...

算法:数组中的最大差值---“打擂台法“

文章来源&#xff1a; https://blog.csdn.net/weixin_45630258/article/details/132737088 欢迎各位大佬指点、三连 1、题目&#xff1a; 给定一个整数数组 nums&#xff0c;找出给定数组中两个数字之间的最大差值。要求&#xff0c;第二个数字必须大于第一个数字。 2、分析特…...

三种方式查看 JVM 垃圾收集器

一、引言 不同版本的 JVM 默认使用的垃圾收集器是不同的&#xff0c;目前的新生代和老年代的垃圾收集器如下图所示&#xff0c;新生代和老年代之间的连线表示这些垃圾收集器可以进行搭配使用 垃圾收集器的名字和 JVM 里面的参数对照表如下&#xff0c;即在 JVM 里面并不是存储的…...

React中函数式组件与类组件有何不同?

Function Component 与 Class Component 有何不同 目录 Function Component 与 Class Component 有何不同 文章核心观点&#xff1a; 解释一下&#xff1a; 总结&#xff1a; 文章核心观点&#xff1a; Function components capture the rendered values.函数式组件捕获…...

windows11安装docker时,修改默认安装到C盘

1、修改默认安装到C盘 2、如果之前安装过docker&#xff0c;请删除如下目录&#xff1a;C:\Program Files\Docker 3、在D盘新建目录&#xff1a;D:\Program Files\Docker 4、winr&#xff0c;以管理员权限运行cmd 5、在cmd中执行如下命令&#xff0c;建立软联接&#xff1a; m…...

python模块之 aiomysql 异步mysql

mysql安装教程 mysql语法大全 python 模块pymysql模块&#xff0c;连接mysql数据库 一、介绍 aiomysql 是一个基于 asyncio 的异步 MySQL 客户端库&#xff0c;用于在 Python 中与 MySQL 数据库进行交互。它提供了异步的数据库连接和查询操作&#xff0c;适用于异步编程环境 …...

开开心心带你学习MySQL数据库之第八篇

索引和事务 ~~ 数据库运行的原理知识 面试题 索引 索引(index) > 目录 索引存在的意义,就是为了加快查找速度!!(省略了遍历的过程) 查找速度是快了&#xff0c;但是付出了一定的代价!! 1.需要付出额外的空间代价来保存索引数据 2.索引可能会拖慢新增,删除,修改的速度 ~~ …...

yml配置动态数据源(数据库@DS)与引起(If you want an embedded database (H2, HSQL or Derby))类问题

1&#xff1a;yml 配置 spring:datasource:dynamic:datasource:master:url: jdbc:mysql://192.168.11.50:3306/dsdd?characterEncodingUTF-8&useUnicodetrue&useSSLfalse&tinyInt1isBitfalse&allowPublicKeyRetrievaltrue&serverTimezoneUTCusername: ro…...

yolov5运行过程遇到的小问题(随时更新)

1.关于git的问题 解决办法&#xff1a;插入下面代码 import os os.environ["GIT_PYTHON_REFRESH"] "quiet"2.页面太小无法完成操作 解决办法: 如果不好使再考虑降低Batch_Size大小或者调整虚拟内存可用硬盘空间大小&#xff01;&#xff08;调整虚拟内存…...

使用FabricJS创建Image对象的JSON表示

本篇文章介绍一下如何创建图像的 JSON 表示形式 使用 FabricJS 的对象。我们可以通过创建一个实例来创建一个 Image 对象 织物.图像。由于它是FabricJS的基本元素之一&#xff0c;我们也可以轻松地 通过应用角度、不透明度等属性来自定义它。为了创建 JSON Image 对象的表示&am…...

【牛客刷题】反转固定区间链表、每k个节点一组反转

链表内指定区间反转_牛客题霸_牛客网 ListNode* reverseList(ListNode* head, ListNode* tail) {ListNode* pre nullptr;ListNode* cur head;while (cur ! tail) { 最后cur就是tailListNode* temp cur->next;cur->next pre;pre cur;cur temp;}return pre;}ListNode…...

算法:数组常见套路1---双指针、取模、打擂台法

文章来源&#xff1a; https://blog.csdn.net/weixin_45630258/article/details/132738318 欢迎各位大佬指点、三连 一、数组的合并–双指针[快慢指针] 1、题目&#xff1a; 给你两个按 非递减顺序 排列的整数数组 nums1 和 nums2&#xff0c;另有两个整数 m 和 n &#xff0…...

App 出海实践:Google Play 结算系统

作者&#xff1a;业志陈 现如今&#xff0c;App 出海热度不减&#xff0c;是很多公司和个人开发者选择的一个市场方向。App 为了实现盈利&#xff0c;除了接入广告这种最常见的变现方式外&#xff0c;就是通过提供各类虚拟商品或者是会员服务来吸引用户付费了&#xff0c;此时 …...

国际慈善日 | 追寻大爱无疆,拓世科技集团的公益之路

每年的9月5日&#xff0c;是联合国大会正式选定的国际慈善日。这一天的设立&#xff0c;旨在通过提高公众对慈善活动的意识&#xff0c;鼓励慈善公益活动通过各种形式在全球范围内得到增强和发展。这是一个向慈善公益事业致敬的日子&#xff0c;同时也是呼吁全球团结一致共同发…...

树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频

使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源&#xff1a; http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...

在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能

下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能&#xff0c;包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容

基于 ​UniApp + WebSocket​实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配​微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

JVM垃圾回收机制全解析

Java虚拟机&#xff08;JVM&#xff09;中的垃圾收集器&#xff08;Garbage Collector&#xff0c;简称GC&#xff09;是用于自动管理内存的机制。它负责识别和清除不再被程序使用的对象&#xff0c;从而释放内存空间&#xff0c;避免内存泄漏和内存溢出等问题。垃圾收集器在Ja…...

苍穹外卖--缓存菜品

1.问题说明 用户端小程序展示的菜品数据都是通过查询数据库获得&#xff0c;如果用户端访问量比较大&#xff0c;数据库访问压力随之增大 2.实现思路 通过Redis来缓存菜品数据&#xff0c;减少数据库查询操作。 缓存逻辑分析&#xff1a; ①每个分类下的菜品保持一份缓存数据…...

项目部署到Linux上时遇到的错误(Redis,MySQL,无法正确连接,地址占用问题)

Redis无法正确连接 在运行jar包时出现了这样的错误 查询得知问题核心在于Redis连接失败&#xff0c;具体原因是客户端发送了密码认证请求&#xff0c;但Redis服务器未设置密码 1.为Redis设置密码&#xff08;匹配客户端配置&#xff09; 步骤&#xff1a; 1&#xff09;.修…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

scikit-learn机器学习

# 同时添加如下代码, 这样每次环境(kernel)启动的时候只要运行下方代码即可: # Also add the following code, # so that every time the environment (kernel) starts, # just run the following code: import sys sys.path.append(/home/aistudio/external-libraries)机…...

沙箱虚拟化技术虚拟机容器之间的关系详解

问题 沙箱、虚拟化、容器三者分开一一介绍的话我知道他们各自都是什么东西&#xff0c;但是如果把三者放在一起&#xff0c;它们之间到底什么关系&#xff1f;又有什么联系呢&#xff1f;我不是很明白&#xff01;&#xff01;&#xff01; 就比如说&#xff1a; 沙箱&#…...

​​企业大模型服务合规指南:深度解析备案与登记制度​​

伴随AI技术的爆炸式发展&#xff0c;尤其是大模型&#xff08;LLM&#xff09;在各行各业的深度应用和整合&#xff0c;企业利用AI技术提升效率、创新服务的步伐不断加快。无论是像DeepSeek这样的前沿技术提供者&#xff0c;还是积极拥抱AI转型的传统企业&#xff0c;在面向公众…...