C语言易错知识点十(指针(the final))
❀❀❀ 文章由@不准备秃的大伟原创 ❀❀❀
♪♪♪ 若有转载,请联系博主哦~ ♪♪♪
❤❤❤ 致力学好编程的宝藏博主,代码兴国!❤❤❤
许久不见,甚是想念,真的是时间时间,你慢些吧,不能再让头发变秃了 ,我愿用我一生换我头发常青~~(^▽^ )。好的好的,今天是12月31号,是2023年的最后一天,博主这里提前祝大家新年快乐!

最后一天了, 博主在这里问各位铁汁们一句:“2022年定下的目标2023年都实现了吗?2023又要为2024定什么目标呢?” 或许有些铁汁会骄傲的拍拍胸脯说:“何止实现了,我还超了呢!”,或许也有铁汁会说:“嗐,2023年因为这样那样的原因,没有能完成去年定的目标,很后悔!”
其实无论你是处在哪种阶段,博主只想说:“向前看吧,过去的已经不存在了,过去一年里你是荣华富贵或是灰头土脸又如何,难道以后就不会改变了吗?就像我们头上的头发,终有一天也会变白,脱落,但是生活不还得继续吗?所以,抛下顾虑,放下过去的荣辱,在新的一年里继续努力,为更好的未来而前进吧!”
鸡汤虽多,但不喝也无用。所以,为了更好的未来,我们铁汁们还是需要继续学习的是吧,还会继续给大伟点赞收藏,继续支持大伟的对吧~对吧~对吧~ヾ(≧▽≦*)o
呃哼,我们今天来看看C语言的核心:指针的最后一篇。今天我们要学的知识是:没了。

啊不是,应该是有关指针的内容基本没了,这一篇主要是一些扩展,别误解哦~ 好的,今天要学的内容是:回调函数,qsort使用和模拟实现,最后是有关指针的笔试题。
诶,但是在开始之前,我们先谈一谈上一篇博客最后提到的两段代码,什么,不记得了?哼,就知道会发生这种情况,快去看—————>指针(part three)
一.
(*(void (*)())0)();
大家整体看这段代码是不是难于理解?那如果我们把它分为几个区块,从内部一个一个分析呢?:
void (*)()
这是一个函数指针的声明。它声明了一个指向不带参数(void)并返回 void 的函数的指针
(void (*)())0
这是将整数 0 转换为指定类型的函数指针
(*(void (*)())0)
这对函数指针进行了解引用。它将地址为 0 的值视为函数并调用它
简单来说,这段代码试图调用内存地址为 0 处的函数
怎么说,铁汁们,从内部一步一步分解是不是就会相对好理解了?里面的内容其实是我们已经学过的知识的集合体啊,对不对。
二.那么根据以上的思路,兄弟们自己再试图理解理解下面这个代码:
void (*signal(int , void(*)(int)))(int);
——————————————————————————————————————————
signal
这是一个函数名
int
这是signal函数的第一个参数,表示信号编号
void(*)(int)
这是signal函数的第二个参数,是一个函数指针。它表示指向一个接受int参数并返回void的函数的指针。这个函数指针是信号处理函数,指定了在接收到信号时应采取的操作
(*signal(int, void(*)(int)))
这部分表示signal是一个接受两个参数并返回某种结果的函数。声明的最外层指定了返回的类型
void(*)(int)
这指定了signal函数的返回类型。它是一个函数指针,指向一个接受int参数并返回void的函数。这与signal返回信号处理函数的函数指针的概念一致
综合起来,signal函数接受两个参数:一个表示信号编号的int,一个表示信号处理函数的函数指针。它返回一个类型为void (*)(int)的函数指针
OK,这里把上一篇博客遗留下的问题解决了,现在开始这次的内容:
回调函数
定义:回调函数就是⼀个通过函数指针调⽤的函数
简单来说:就是在函数内定义了另一个函数 ,如:
int add(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()
{
calc(add);
return 0;
}
calc函数接受一个函数指针 pf,该指针指向一个接受两个整数参数并返回整数的函数。
qsort使用及实现
以下是qsort函数的使用演示:
#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]);}return 0;
}
以下是cpp官方给的qsort的解释:
其中的四个元素:
还是那句话,虽然我们程序猿不需要多好的英语,但是我们以后是需要看各种英文的文献的,所以我们从现在开始就要逐渐适应读英文的文章。
简单来说:qsort函数内部第一个元素:要排序的数组名,第二个元素:数组的大小,第三个元素:数组内存储的类型的字节大小,第四个元素:一个cmp函数,函数内实现的是两个指针的对比。(如上,*a -*b为升序,*b - *a 为降序,*a > *b 为升序,*a < *b 为降序)
拓展一下:qsort库函数底层是快排,时间复杂度是O(N*logN) ,在我们刷题的时候还蛮经常用的。
那现在我们来对qsort函数进行个模拟实现,当然,是以冒泡的方法,所以时间复杂度是O(N*N)。那我们来看看吧!:
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 };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;
}
这个模拟实现是完全按照官方给的元素来写的,浓度比较高,大家好好吸收哦~
指针笔试题
其实的话到这里有关指针的内容已经可以结束了,但是呢,学而不思则罔,学会了,还需要大量的练习,正如前段时间网上比较火的:
题目是做不完的,但是知识点是固定的,博主这里给大家出三道题,大家珍惜哦~
一.
int main()
{int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };int *ptr1 = (int *)(&aa + 1);int *ptr2 = (int *)(*(aa + 1));printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));return 0;
}
解析:&aa+1越过了整个二维数组aa,所以ptr1指向的是二维数组后面的那个元素,然后ptr-1,指向的是10;而aa+1越过了整个二维数组的第一行,ptr2指向的是6,ptr2-1指向的是aa第一行的最后一个元素5。
答案就是10和5
二.
int main()
{char *a[] = {"work","at","alibaba"};char**pa = a;pa++;printf("%s\n", *pa);return 0;
}
定义了一个指针数组*a[],又定义了一个二级pa指向a的首元素“work”,pa++也就是a向后走一个元素,此时*pa就是“at”。
答案就是at
三.
int main()
{char *c[] = {"ENTER","NEW","POINT","FIRST"};char**cp[] = {c+3,c+2,c+1,c};char***cpp = cp;printf("%s\n", **++cpp);printf("%s\n", *--*++cpp+3);printf("%s\n", *cpp[-2]+3);printf("%s\n", cpp[-1][-1]+1);return 0;
}
同二,二级指针cp内存放的是将*c内元素逆转过来的,而三级指针指向的就是cp首元素,所以**++cpp就是指向的cpp向后走一个元素,即c+2,即“POINT”;*--*++cpp+3就是++cpp 指向 cp 数组的下一个元素,*--*++cpp 得到一个指向 c[0] 的指针 "ENTER",然后 +3 得到 "ER" ;*cpp[-2]+3 中 cpp[-2] 得到 cp[0],*cpp[-2] 得到 c[3],然后 +3 得到 "ST";cpp[-1][-1]+中,cpp[-1] 即*(cpp-1)得到 cp[2],cpp[-1][-1] 即 *(*(cpp-1)-1) 得到 c[1],然后 +1 得到 "EW"。答案就是POINT ER ST EW
C语言指针也就到此为止了,最后再次祝大家新年快乐,愿大家成为自己心目中的那个人。插一嘴哈~虽然指针结束了,但大伟的学习和博客还没有结束哦,希望大家以后继续支持大伟,加油!
衣带渐宽终不悔,为伊(知识)消得人憔悴 ------柳永
本篇博客也就到此为止了,送大家一碗鸡汤,勉励自己以及这世界上所有追逐梦想的赤子趁年华尚好努力提升自己,莫欺少年穷! 
相关文章:
C语言易错知识点十(指针(the final))
❀❀❀ 文章由不准备秃的大伟原创 ❀❀❀ ♪♪♪ 若有转载,请联系博主哦~ ♪♪♪ ❤❤❤ 致力学好编程的宝藏博主,代码兴国!❤❤❤ 许久不见,甚是想念,真的是时间时间,你慢些吧,不能再让头发变秃…...
React 18 新增的钩子函数
React 18 引入了一些新的钩子函数,用于处理一些常见的场景和问题。以下是 React 18 中引入的一些新钩子函数以及它们的代码示例和使用场景: useTransition: 代码示例:import { useTransition } from react;function MyComponent()…...
安装与部署Hadoop
一、前置安装准备1、机器2、java3、创建hadoop用户 二、安装Hadoop三、环境配置1、workers2、hadoop-env.sh3、core-site.xml4、hdfs-site.xml5、linux中Hadoop环境变量 四、启动hadoop五、验证 一、前置安装准备 1、机器 主机名ip服务node1192.168.233.100NameNode、DataNod…...
MySQL 8.0 InnoDB Tablespaces之General Tablespaces(通用表空间/一般表空间)
文章目录 MySQL 8.0 InnoDB Tablespaces之General Tablespaces(通用表空间/一般表空间)General tablespaces(通用表空间/一般表空间)通用表空间的功能通用表空间的限制 创建通用表空间(一般表空间)创建语法…...
循环生成对抗网络(CycleGAN)
一、说明 循环生成对抗网络(CycleGAN)是一种训练深度卷积神经网络以执行图像到图像翻译任务的方法。网络使用不成对的数据集学习输入和输出图像之间的映射。 二、基本介绍 CycleGAN 是图像到图像的翻译模型,就像Pix2Pix一样。Pix2Pix模型面临…...
数组--53.最大子数组和/medium
53.最大子数组和 1、题目2、题目分析3、解题步骤4、复杂度最优解代码示例5、抽象与扩展 1、题目 给你一个整数数组 nums ,请你找出一个具有最大和的连续子数组(子数组最少包含一个元素),返回其最大和。 子数组 是数组中的一个连…...
centos 编译安装 python 和 openssl
安装环境: centos 7.9 : python 3.10.5 和 openssl 3.0.12 centos 6.10 : python 3.10.5 和 openssl 1.1.1 两个环境都能安装成功,可以正常使用。 安装 openssl 下载地址 下载后解压,进入到解压目录 执行…...
【nodejs】前后端身份认证
前后端身份认证 一、web开发模式 服务器渲染,前后端分离。 不同开发模式下的身份认证: 服务端渲染推荐使用Session认证机制前后端分离推荐使用JWT认证机制 二、session认证机制 1.HTTP协议的无状态性 了解HTTP协议的无状态性是进一步学习Session认…...
数据结构【线性表篇】(三)
数据结构【线性表篇】(三) 文章目录 数据结构【线性表篇】(三)前言为什么突然想学算法了?为什么选择码蹄集作为刷题软件? 目录一、双链表二、循环链表三、静态链表 结语 前言 为什么突然想学算法了? > 用较为“官方…...
Python装饰器的专业解释
装饰器,其实是用到了闭包的原理来进行操作的。 单个装饰器: 以下是一个简单的例子: def outer(func):print("OUTER enter ...")def wrapper(*args, **kwargs):print("调用之前......")result func(*args, **kwargs)p…...
vue3框架笔记
Vue Vue 是一个渐进式的前端开发框架,很容易上手。Vue 目前的版本是 3.x,但是公司中也有很多使用的是 Vue2。Vue3 的 API 可以向下兼容 2,Vue3 中新增了很多新的写法。我们课程主要以 Vue3 为主 官网 我们学习 Vue 需要转变思想࿰…...
pytest --collectonly 收集测试案例
pytest --collectonly 是一条命令行指令,用于在运行 pytest 测试时仅收集测试项而不执行它们。它会显示出所有可用的测试项列表,包括测试模块、测试类和测试函数,但不会执行任何实际的测试代码。 这个命令对于查看项目中的测试结构和确保所有…...
dev express 15.2图表绘制性能问题(dotnet绘图表)
dev express 15.2 绘制曲线 前端代码 <dxc:ChartControl Grid.Row"1"><dxc:XYDiagram2D EnableAxisXNavigation"True"><dxc:LineSeries2D x:Name"series" CrosshairLabelPattern"{}{A} : {V:F2}"/></dxc:XYDi…...
WorkPlus:领先的IM即时通讯软件,打造高效沟通协作新时代
在当今快节奏的商业环境中,高效沟通和协作是企业成功的关键。而IM即时通讯软件作为实现高效沟通的利器,成为了现代企业不可或缺的一部分。作为一款领先的IM即时通讯软件,WorkPlus以其卓越的性能和独特的功能,助力企业打造高效沟通…...
学习SpringCloud微服务
SpringCloud 微服务单体框架微服务框架SpringCloud微服务拆分微服务差分原则拆分商品服务拆分购物车服务拆分用户服务拆分交易服务拆分支付服务服务调用RestTemplate远程调用 微服务拆分总结 服务治理注册中心Nacos注册中心服务注册服务发现 OpenFeign实现远程调用快速入门引入…...
WPF 显示气泡提示框
气泡提示框应用举例 有时候在我们开发的软件经常会遇到需要提示用户的地方,为了让用户更直观,快速了解提示信息,使用简洁、好看又方便的气泡提示框显得更加方便,更具人性化。如下面例子:(当用户未输入账号时࿰…...
L1-062:幸运彩票
题目描述 彩票的号码有 6 位数字,若一张彩票的前 3 位上的数之和等于后 3 位上的数之和,则称这张彩票是幸运的。本题就请你判断给定的彩票是不是幸运的。 输入格式: 输入在第一行中给出一个正整数 N(≤ 100)。随后 N 行…...
python+vue高校体育器材管理信息系统5us4g
优秀的高校体育馆场地预订系统能够更有效管理体育馆场地预订业务规范,帮助管理者更加有效管理场地的使用,有效提高场地使用效率,可以帮助提高克服人工管理带来的错误等不利因素,所以一个优秀的高校体育馆场地预订系统能够带来很大…...
10 款顶级的免费U盘数据恢复软件(2024 年 更新)
你曾经遇到过U盘无法访问的情况吗?现在我们教你如何恢复数据。 在信息时代,数据丢失往往会造成巨大的困扰。而USB闪存驱动器作为我们常用的数据存储设备,其重要性不言而喻。但是,U盘也可能会出现各种问题,如无法访问、…...
C# json 转匿名对象及C#关键字的处理
调用第三方接口,返回的json字符串,为了方便使用转为C#匿名对象: /// <summary>/// json转为匿名对象/// </summary>/// <typeparam name"T"></typeparam>/// <param name"json"></para…...
第19节 Node.js Express 框架
Express 是一个为Node.js设计的web开发框架,它基于nodejs平台。 Express 简介 Express是一个简洁而灵活的node.js Web应用框架, 提供了一系列强大特性帮助你创建各种Web应用,和丰富的HTTP工具。 使用Express可以快速地搭建一个完整功能的网站。 Expre…...
从零实现富文本编辑器#5-编辑器选区模型的状态结构表达
先前我们总结了浏览器选区模型的交互策略,并且实现了基本的选区操作,还调研了自绘选区的实现。那么相对的,我们还需要设计编辑器的选区表达,也可以称为模型选区。编辑器中应用变更时的操作范围,就是以模型选区为基准来…...
376. Wiggle Subsequence
376. Wiggle Subsequence 代码 class Solution { public:int wiggleMaxLength(vector<int>& nums) {int n nums.size();int res 1;int prediff 0;int curdiff 0;for(int i 0;i < n-1;i){curdiff nums[i1] - nums[i];if( (prediff > 0 && curdif…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
高危文件识别的常用算法:原理、应用与企业场景
高危文件识别的常用算法:原理、应用与企业场景 高危文件识别旨在检测可能导致安全威胁的文件,如包含恶意代码、敏感数据或欺诈内容的文档,在企业协同办公环境中(如Teams、Google Workspace)尤为重要。结合大模型技术&…...
Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
HashMap中的put方法执行流程(流程图)
1 put操作整体流程 HashMap 的 put 操作是其最核心的功能之一。在 JDK 1.8 及以后版本中,其主要逻辑封装在 putVal 这个内部方法中。整个过程大致如下: 初始判断与哈希计算: 首先,putVal 方法会检查当前的 table(也就…...
回溯算法学习
一、电话号码的字母组合 import java.util.ArrayList; import java.util.List;import javax.management.loading.PrivateClassLoader;public class letterCombinations {private static final String[] KEYPAD {"", //0"", //1"abc", //2"…...
深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
【学习笔记】erase 删除顺序迭代器后迭代器失效的解决方案
目录 使用 erase 返回值继续迭代使用索引进行遍历 我们知道类似 vector 的顺序迭代器被删除后,迭代器会失效,因为顺序迭代器在内存中是连续存储的,元素删除后,后续元素会前移。 但一些场景中,我们又需要在执行删除操作…...
