带你深入了解c语言指针后续

前言
🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨
🐻推荐专栏: 🍔🍟🌯 c语言进阶
🔑个人信条: 🌵知行合一
🍉本篇简介:>:介绍c语言中有关指针更深层的知识.
金句分享:
✨在该奋斗的岁月里,✨
✨对得起每一寸光阴.✨
目录
- 前言
- 一、函数指针
- 1.1 函数指针的创建
- 1.2 函数指针应用
- 二、函数指针数组
- 三、函数指针数组指针
- 四、回调函数
一、函数指针
1.1 函数指针的创建
函数指针,顾名思义,就一个指向函数的指针.
那么
整形指针是接收整形的地址;
字符指针是接收字符的地址.
数组指针是接收数组的地址
函数有地址吗?函数名又可以代表什么?
示例:自定义一个加法函数,观察函数的地址
//函数指针
#include <stdio.h>
int add(int a,int b)//自定义一个加法函数
{return a + b;
}
int main()
{int a = 2, b = 3;int c=add(a, b);printf("%d\n", c);//确认一下函数是否正确printf("%p\n", &add);//取出函数的地址printf("%p\n", add);//用数组名打印return 0;
}
运行结果:(在不同环境下地址会不一样,这里采用的是vs x86环境)
5
00E61023
00E61023
不难发现,函数名也可以代表函数的地址.
那么函数指针该怎么写呢?
以数组指针为例:
数组指针示例:写一个指向 int arr[10] 数组的数组指针;
第一步:
(*p) //先确定是一个指针
第二步:
(*p)[10] //确定指向的是一个有10个元素的数组
第三步:
int(*p)[10] //确定该数组元素为int型
第四步:
int(*p)[10]=&arr;//将数组的地址赋值给数组指针
//或者int(*p)[10]=arr;
示例2:
函数指针:指向int add(int a,int b)
第一步:
(*p) //先确定是一个指针
第二步:
(*p)(int,int) //确定指向的函数有两个参数
第三步:
int (*p)(int,int) //确定该函数的返回类型
第四步:
int (*p)(int,int)=&add;//将函数的地址赋值给函数指针
//等价于:int (*p)(int,int)=add;
1.2 函数指针应用
那么函数指针有什么用吗?
当然是用来调用函数了.
同样以数组指针为例:
🌰使用数组指针访问数组.
int main()
{int arr[10] = { 1,2,3,4,5 };int(*p)[10] = arr;for (int i = 0; i < 5; i++){printf("%d ", ( * p)[i]);}printf("\n");return 0;
}
🌰使用函数指针调用函数
#include <stdio.h>
int add(int a,int b)
{return a + b;
}
int main()
{int a = 2, b = 3;int(*p1)(int, int) = &add;int(*p2)(int, int) = add;int ret1=add(a,b);int ret2=(*p1)(a, b);//写法一int ret3=p1(a, b);//写法2printf("ret1=%d\nret2=%d\nret3=%d",ret1,ret2,ret3);return 0;
}
运行结果:都能完成函数的调用
ret1=5
ret2=5
ret3=5
二、函数指针数组
函数指针数组实质用于存放函数指针的数组.
即数组的成员都是函数指针.
写法:以数组成员都是指向类似int add(int,int)的函数指针为例
1.先写出函数指针
(int) (*p)(int,int)
2.改成数组
(int) (*p[10])(int,int)//函数指针数组
题目:使用c语言制作简单的计算器.
要求,可以进行加减乘除运算.
//简易计算器
#include <stdio.h>
void menu()//菜单
{printf("作者:初阶牛\n");printf(" 欢迎使用计算器:\n");printf("+-------------------------------+\n");printf("| 1.add 2.sub |\n");printf("| 3.mul 4.div |\n");printf("| 0.退出 |\n");printf("+-------------------------------+\n");
}
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;
}
int main()
{int x=0, y=0;int input = 1;int ret = 0;do{menu();//打印菜单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>
void menu()
{printf("作者:初阶牛\n");printf(" 欢迎使用计算器:\n");printf("+-------------------------------+\n");printf("| 1.add 2.sub |\n");printf("| 3.mul 4.div |\n");printf("| 0.退出 |\n");printf("+-------------------------------+\n");
}
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;
}
int main()
{int x = 0, y = 0;int input = 1;int ret = 0;int(*arr[5])(int, int)={0,add,sub,mul,div};//使用函数指针数组do{menu();scanf("%d", &input);if (input > 0 && input < 5){printf("输入两个操作数:");scanf("%d %d", &x, &y);ret=arr[input](x,y);//利用数组下标调用相应的函数printf("ret = %d\n", ret);}else if (input == 0){printf("退出计算器\n");break;}else{printf("很遗憾,并没有这个选项:\n");break;}} while (input);return 0;
}
三、函数指针数组指针
函数指针数组指针:
指向一个数组.该数组的成员都是函数指针.
写法:
1.先写出函数指针
char* (*p)(const int, double, char*);
2.改成函数指针数组
char* (*pp[3])(const int, double, char*);
3.最后写成函数指针数组指针char* (*(*ppp)[3])(const int, double, char*);
可以通过函数指针p调用函数,
也可以通过函数指针数组的元素,pp[0]调用函数.
最后,可以通过(*ppp)找到函数指针数组,(*ppp)[0]调用函数.
示例:
char* test(const int a, double b, char* c)
{char* ret = "AAABBBCCCDDD\n";return ret;
}
#include <stdio.h>
int main()
{//函数指针char* (*p)(const int, double, char*)=test;//函数指针数组char* (*pp[3])(const int, double, char*);pp[0] = test;//函数指针数组指针char* (*(*ppp)[3])(const int, double, char*)=&pp;printf("%s", test(0,0,0));printf("%s", p(0, 0, 0));printf("%s", pp[0](0, 0, 0));printf("%s", (*ppp)[0](0, 0, 0));return;
}
四、回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
大家还记得冒泡排序吗?
但是冒泡排序只能排序整形,而qsort函数,内部采用快速排序,可以排序各种类型的数据,接下来展示qsort排序部分类型的方法.
示例:qsort函数部分应用
分别将元素比较方法int_cmp和char_cmp的指针(地址) 传给 qsot函数.由qsort函数调用这些比较函数.
#include <stdlib.h>
#include <stdio.h>
int int_cmp(void* e1, void* e2)//整形元素排序方法
{return *(int*)e1 - *(int*)e2;
}
int char_cmp(void* e1, void* e2)//字符型元素排序方法
{return (*(char*)e1) - (*(char*)e2);
}
int main()
{int arr1[10] = { 4,5,1,8,9,2,10,3,7,6 };char arr2[] = "fbadegc";int sz1 = sizeof(arr1) / sizeof(arr1[0]);int sz2 = sizeof(arr2) / sizeof(arr2[0]);qsort(arr1,sz1,sizeof(arr1[0]),int_cmp);for (int i=0; i < sz1; i++){printf("%d ", arr1[i]);}printf("\n");qsort(arr2, sz2, sizeof(arr2[0]), char_cmp);for (int i = 0; i < sz2; i++){printf("%c ", arr2[i]);}printf("%s", arr2);return 0;
}
运行结果:
1 2 3 4 5 6 7 8 9 10
a b c d e f g
qsort函数用冒泡排序的模拟实现,以及各种类型的排序.这周会加更出来的,好文不怕晚.🤣🤣🤣
最后,如果文章对大家有帮助的话,求一波三连吧!
💗💗💗886

相关文章:
带你深入了解c语言指针后续
前言 🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨ 🐻推荐专栏: 🍔🍟🌯 c语言进阶 🔑个人信条: 🌵知行合一 🍉本篇简介:>:介绍c语言中有关指针更深层的知识. 金句分享: ✨在该…...
借助Intune无感知开启Bitlocker
希望使用 Intune 部署 BitLocker,但不知道从哪里开始?这是人们最开始使用 Intune 时最常见的问题之一。在本博客中,你将了解有关使用 Intune 管理 BitLocker 的所有信息,包括建议的设置、BitLocker CSP 在客户端上的工作方式&…...
零基础该如何转行Python工程师?学习路线是什么?
最近1年的主要学习时间,都投资到了 python 数据分析和数据挖掘上面来了,虽然经验并不是十分丰富,但希望也能把自己的经验分享下,最近也好多朋友给我留言,和我聊天,问我python该如何学习,才能少走…...
Go项目(商品微服务-1)
文章目录简介建表protohandler商品小结简介 商品微服务主要在于表的设计,建哪些表?表之间的关系是怎样的? 主要代码就是 CURD表和字段的设计是一个比较有挑战性的工作,比较难说清楚,也需要经验的积累,这里…...
机器学习——集成学习
引言 集成学习:让机器学习效果更好,单个不行,群殴走起。 分类 1. Bagging:训练多个分类器取平均(m代表树的个数)。 2.Boosting(提升算法):从弱学习器开始加,通过加权来进行训练。…...
VS编译系统 实用调试技巧
目录什么是bug?调试是什么?有多重要?debug和release的介绍windows环境调试介绍、一些调试实例如何写出(易于调试)的代码编程常见的错误什么是bug?其实bug在英文翻译中有表示臭虫的含义,因为第一次被发现的导致计算机…...
【华为OD机试模拟题】用 C++ 实现 - GPU 调度(2023.Q1)
最近更新的博客 【华为OD机试模拟题】用 C++ 实现 - 去重求和(2023.Q1) 文章目录 最近更新的博客使用说明GPU 调度题目输入输出示例一输入输出说明示例二输入输出说明Code使用说明 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。...
腾讯前端必会react面试题合集
React-Router的路由有几种模式? React-Router 支持使用 hash(对应 HashRouter)和 browser(对应 BrowserRouter) 两种路由规则, react-router-dom 提供了 BrowserRouter 和 HashRouter 两个组件来实现应用的…...
Linux搭建SVN服务器,并内网穿透实现公网远程访问
文章目录1. Ubuntu安装SVN服务2. 修改配置文件2.1 修改svnserve.conf文件2.2 修改passwd文件2.3 修改authz文件3. 启动svn服务4. 内网穿透4.1 安装cpolar内网穿透4.2 创建隧道映射本地端口5. 测试公网访问6. 配置固定公网TCP端口地址6.1 保留一个固定的公网TCP端口地址6.2 配置…...
C++STL之list的模拟实现
目录 一.list准备 二. iterator迭代器 1._list_iterator 2.begin()、end() 3.const_begin()、const_end() 4.!&& 5. && -- 6.operator* 7.operator-> 三.Modify(修改) 1.insert() 2.erase() 3.push_back() && push_front() 4.pop_bac…...
为什么硬件性能监控很重要
当今的混合网络环境平衡了分布式网络和现代技术的实施。但它们并不缺少一个核心组件:服务器。保持网络正常运行时间归结为监控和管理导致网络停机的因素。极有可能导致性能异常的此类因素之一是硬件。使用硬件监控器监控网络硬件已成为一项关键需求。 硬件监视器是…...
HTTP缓存
HTTP缓存HTTP缓存引发的一个问题HTTP缓存的作用HTTP缓存的分类强制缓存协商缓存(解决强缓存下资源不更新问题)缓存策略HTTP缓存引发的一个问题 有一次在开发移动端H5项目,UI提了几个UI问题,经过样式调试,android上没有…...
SPI设备树处理过程
SPI设备树处理过程 文章目录SPI设备树处理过程参考资料:一、 spi_device结构体二、 SPI设备树格式2.1 SPI Master2.2 SPI Device2.3 设备树示例三、设备树实例3.1 使用GPIO模拟的SPI控制器3.2 IMX6ULL SPI控制器四、 设备树处理过程致谢参考资料: 内核头…...
数据有哪些重要的作用?
我们正处在科技高速发展的时代,如今互联网已经与我们的生活息息相关,我们每天在互联网产生大量的数据,这些数据散落在网络中看似没有怎么作用,但是这些数据经过系统的处理整合起来确实非常有价值的。 一、 发展大数据技术可以提高…...
spring面试题总结
1、spring是什么? spring是一个轻量级IOC和AOP容器框架,是为Java应用程序提供基础性服务的一套框架,目的是用于简化企业应用的开发,开发者只需要关注业务需求即可: core container 容器组件 spring context,…...
使用MUI与H5+构建移动端app
前言 通过mui构建APP 效果图: <!DOCTYPE html> <html> <head><meta charset...
第17篇:Java变量总结
目录 1.变量的概念 1.1 变量来源 1.2 计算机中的变量 1.3 变量如何在内存中存储 2.Java变量...
使用51单片机的GPIO输出占空比可调节的PWM波
一、前言 在一些单片机或微控制器中,通用GPIO可以被配置为产生PWM信号。PWM即脉冲宽度调制,是一种用于模拟输出的技术。它可以通过改变输出信号的脉冲宽度来控制电路中的电平,从而实现对电路的控制。 二、什么是PWM波? PWM波&a…...
从产品经理的角度如何提升项目的交付质量?
提高交付质量 ,对于每个IT公司都是永恒的话题。 交付质量其实包含2重意义, 一是交付的高质量(客户角度),即客户的满意度;二是高质量的交付(交付团队的角度),这里是指如何…...
JavaScript BOM【快速掌握知识点】
目录 Window对象的常用属性 语法: Window对象的常用方法 语法: open()和close()方法 History对象 常用属性和方法 示例 Location对象 常用属性 常用方法 Document对象的常用方法 定时函数 超时调用:setTimeout() 间歇调用&…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
【网络安全产品大调研系列】2. 体验漏洞扫描
前言 2023 年漏洞扫描服务市场规模预计为 3.06(十亿美元)。漏洞扫描服务市场行业预计将从 2024 年的 3.48(十亿美元)增长到 2032 年的 9.54(十亿美元)。预测期内漏洞扫描服务市场 CAGR(增长率&…...
UE5 学习系列(三)创建和移动物体
这篇博客是该系列的第三篇,是在之前两篇博客的基础上展开,主要介绍如何在操作界面中创建和拖动物体,这篇博客跟随的视频链接如下: B 站视频:s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
大学生职业发展与就业创业指导教学评价
这里是引用 作为软工2203/2204班的学生,我们非常感谢您在《大学生职业发展与就业创业指导》课程中的悉心教导。这门课程对我们即将面临实习和就业的工科学生来说至关重要,而您认真负责的教学态度,让课程的每一部分都充满了实用价值。 尤其让我…...
GC1808高性能24位立体声音频ADC芯片解析
1. 芯片概述 GC1808是一款24位立体声音频模数转换器(ADC),支持8kHz~96kHz采样率,集成Δ-Σ调制器、数字抗混叠滤波器和高通滤波器,适用于高保真音频采集场景。 2. 核心特性 高精度:24位分辨率,…...
用机器学习破解新能源领域的“弃风”难题
音乐发烧友深有体会,玩音乐的本质就是玩电网。火电声音偏暖,水电偏冷,风电偏空旷。至于太阳能发的电,则略显朦胧和单薄。 不知你是否有感觉,近两年家里的音响声音越来越冷,听起来越来越单薄? —…...
AGain DB和倍数增益的关系
我在设置一款索尼CMOS芯片时,Again增益0db变化为6DB,画面的变化只有2倍DN的增益,比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析: 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...
Linux 中如何提取压缩文件 ?
Linux 是一种流行的开源操作系统,它提供了许多工具来管理、压缩和解压缩文件。压缩文件有助于节省存储空间,使数据传输更快。本指南将向您展示如何在 Linux 中提取不同类型的压缩文件。 1. Unpacking ZIP Files ZIP 文件是非常常见的,要在 …...
