【C语言】指针剖析(完结)

©作者:末央&

©系列:C语言初阶(适合小白入门)
©说明:以凡人之笔墨,书写未来之大梦

在这里插入图片描述

目录

  • 回调函数
    • 概念
    • 回调函数的使用 - qsort函数
  • sizeof/strlen深度理解
    • 概念
    • 手脑并用
      • 1.sizeof-数组/指针专题
      • 2.strlen-数组/指针专题
    • 指针面试题专题

回调函数

概念

回调函数就是一个通过调用函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

例如:

#include<stdio.h>
void test1()
{printf("hello\n");
}
void test2(void(*p)())
{p(); //指针p被用来调用其所指向的函数
}
int main()
{test2(test1);//将test1函数的地址传递给test2return 0;
}

在该代码中test1函数不是由该函数的实现方直接调用,而是将其地址传递给test2函数,在test2函数中通过函数指针间接调用了test1函数,那么函数test1就被称为回调函数。

回调函数的使用 - qsort函数

其实回调函数并不是很难见到,在用于快速排序的库函数qsort中便运用了回调函数。

void qsort(void*base,size_t num,size_t width,int(*compare)(const void*e1,const void*e2));

qsort函数的第一个参数是待排序的内容的起始位置;第二个参数是从起始位置开始,待排序的元素个数;第三个参数是待排序的每个元素的大小,单位是字节;第四个参数是一个函数指针。qsort函数的返回类型为void。
qsort函数的第四个参数是一个函数指针,该函数指针指向的函数的两个参数的参数类型均为const void*,返回类型为int。当参数e1小于参数e2时返回小于0的数;当参数e1大于参数e2时返回大于0的数;当参数e1等于参数e2时返回0。

列如,我们要排一个整型数组:

#include<stdio.h>
int compare(const void* e1, const void* e2)
{return *((int*)e1) - *((int*)e2);
}//自定义的比较函数
int main()
{int arr[] = { 2, 5, 1, 8, 6, 10, 9, 3, 5, 4 };int sz = sizeof(arr) / sizeof(arr[0]);//元素个数qsort(arr, sz, 4, compare);//用qsort函数将arr数组排序return 0;
}

注意:qsort函数默认将待排序的内容排为升序,如果我们要排为降序可将自定义的比较函数的两个形参的位置互换一下即可。(本来是a>b交换(升序),结果b>a交换(降序))

在qsort函数中我们传入了一个函数指针,最终qsort函数会在其内部通过该函数指针调用该函数,那么我们的这个自定义比较函数就被称为回调函数。

sizeof/strlen深度理解

概念

在这里插入图片描述

手脑并用

1.sizeof-数组/指针专题

//x86环境
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a+0));	//1
printf("%d\n", sizeof(*&a));//2
char arr[] = "abcdef";
printf("%d\n", sizeof(*arr));//3
int a[3][4] = { 0 };
printf("%d\n", sizeof(a[0] + 1));//4
printf("%d\n", sizeof(a + 1));//5
printf("%d\n", sizeof(*(a + 1)));//6
printf("%d\n", sizeof(a[3]));//7

1.这里不同于我们常见的sizeof(a)我们在不是单独一个数组名a在sizeof里面,所以我们计算的不是整个数组的大小。这里a数组名是首元素地址,指针就是地址地址就是指针,地址+0不变,指针大小在x86环境下4,x64环境下为8。所以答案是4

2.这里有两种角度来解释
角度一:
*和&抵消了(上一章提到过),就是sizeof(a)计算整个数组的大小为16
角度二:
&a是数组的地址,数组的地址是不是要用一个数组指针来存放。int( * )[4]是数组指针变量类型, 而 * 的访问字节数取决于变量类型,那么就是访问16个字节的数组指针。

3.*arr,arr是首元素地址,*找到字符’a’,sizeof()计算’a’占用空间,结果为1字节

4.和第1题有一点相似,这里要注意a[0]是一维数组的数组名(二维数组的每个元素是一个一维数组),而数组名没有单独放在sizeof内部而是+1,地址+1还是一个地址a[1],则为4(x86环境)

5.这里很容易加1加为整个二维数组,其实不是,还是同上一题,a为二维数组名但是不是单独放在sizeof内部,则数组名是首元素地址而不是计算整个二维数组大小,数组首元素是第一个一维数组,+1就是指向第二个一维数组的地址,地址结果就为4

6.这里还记得我们上一节讲的指针和数组互化公式吗*(数组名+变量/常量)=数组名[变量/常量]这里*(a+1)=a[1],就是第二个一位数组名,为16

7.或许有很多人看了一眼就直接说是越界访问,理论上有道理,但是我们都忽略了sizeof他实际上不会真正去计算表达式的,他是不会访问a[3]这块空间的,他是靠表达式结果的类型来出结果的,a[3]的类型就是int 4就为16

总结:如果遇到很难分析的题目,就记住一点sizeof里面的表达式并不会真正计算,他的结果是取决于表达式结果的类型包括sizeo(a[0]+1)他的表达式结果是一个地址,地址的类型是指针,指针就是4/8个字节。其他以此类推

2.strlen-数组/指针专题

//x86环境
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", strlen(*arr));	//1
char* p = "abcdef";
printf("%d\n", strlen(&p));	//2

1.这个代码有问题,arr是首元素地址,*arr找到首元素arr[0],就是’a’,然后strlen函数参数是需要一个地址,他会把’a’==97当作一个地址来访问,可是我们并没有97这个地址的访问权限,这里就会形成非法访问
2.这里我们直接上图
在这里插入图片描述
这里我们可以直接看到他们&p和p的地址明显不一样,p是指针变量,存储的是"abcdef"这个常量字符串的地址。而&p是一个地址是指针变量的地址.所以在这个地址不知道什么时候遇到\0,故而结果为随机值

指针面试题专题

//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结构是啥?
struct Test
{
```int Num;char *pcName;short sDate;char cha[2];short sBa[4];
}*p = (struct Test*)0x100000;
int main()
{printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;
}

第一个就是结构体指针+1,既然是指针他的±运算就取决于他的指针类型,int*一次跳过4个字节,题目中告知结构体大小是20字节。所以我们+1就跳过20个字节,则16进制表示100014

第二个很容易出错,把他强制转换为unsigned long形,这是无符号整数+1就是100001

第三个则是无符号整形指针+1,类型一次跳过4个字节,则为100004

//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
int main()
{int a[5][5];int(*p)[4];p = a;printf( "%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);return 0;
}

这里我们之间用一张图来阐述:
在这里插入图片描述
p是一个int(*)[4]的数组指针,但是a的类型是int( * )[5],所以我们第一个值和第二个值按理来说都是负数,但是第一个值是以地址的形式来输出,"地址在内存中不分原反补码,但是-4在内存中是以补码的形式存储,所以直接打印FF FF FF FC

第二个打印原码-4

#include <stdio.h>
int main()
{char *a[] = {"work","at","alibaba"};char**pa = a;pa++;printf("%s\n", *pa);return 0;
}

在这里插入图片描述

指针数组a每一个元素是一个char指针,pa存储第一个元素char地址,+1就是指向下一个元素(另外一个char*),打印他的字符串at
4.

#include <stdio.h>
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;
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
结果就是:
在这里插入图片描述

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

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

相关文章

谷粒商城-个人笔记(集群部署篇二)

前言 ​学习视频&#xff1a;​Java项目《谷粒商城》架构师级Java项目实战&#xff0c;对标阿里P6-P7&#xff0c;全网最强​学习文档&#xff1a; 谷粒商城-个人笔记(基础篇一)谷粒商城-个人笔记(基础篇二)谷粒商城-个人笔记(基础篇三)谷粒商城-个人笔记(高级篇一)谷粒商城-个…

【数据结构】02.顺序表

一、顺序表的概念与结构 1.1线性表 线性表&#xff08;linear list&#xff09;是n个具有相同特性的数据元素的有限序列。线性表是⼀种在实际中广泛使用的数据结构&#xff0c;常见的线性表&#xff1a;顺序表、链表、栈、队列、字符串… 线性表在逻辑上是线性结构&#xff0…

GEE计算遥感生态指数RSEI

目录 RESI湿度绿度热度干度源代码归一化函数代码解释整体的代码功能解释:导出RSEI计算结果参考文献RESI RSEI = f (Greenness,Wetness,Heat,Dryness)其遥感定义为: RSEI = f (VI,Wet,LST,SI)式中:Greenness 为绿度;Wetness 为湿度;Thermal为热度;Dryness 为干度;VI 为植被指数…

【多媒体】Java实现MP4和MP3音视频播放器【JavaFX】【音视频播放】

在Java中播放音视频可以使用多种方案&#xff0c;最常见的是通过Swing组件JFrame和JLabel来嵌入JMF(Java Media Framework)或Xuggler。不过&#xff0c;JMF已经不再被推荐使用&#xff0c;而Xuggler是基于DirectX的&#xff0c;不适用于跨平台。而且上述方案都需要使用第三方库…

拒绝信息差!一篇文章说清Stable Diffusion 3到底值不值得冲

前言 就在几天前&#xff0c;Stability AI正式开源了Stable Diffusion 3 Medium&#xff08;以下简称SD3M&#xff09;模型和适配CLIP文件。这家身处风雨飘摇中的公司&#xff0c;在最近的一年里一直处于破产边缘&#xff0c;就连创始人兼CEO也顶不住压力提桶跑路。 即便这样&…

[leetcode]minimum-absolute-difference-in-bst 二叉搜索树的最小绝对差

. - 力扣&#xff08;LeetCode&#xff09; /*** Definition for a binary tree node.* struct TreeNode {* int val;* TreeNode *left;* TreeNode *right;* TreeNode() : val(0), left(nullptr), right(nullptr) {}* TreeNode(int x) : val(x), left(null…

LeetCode 196, 73, 105

目录 196. 删除重复的电子邮箱题目链接表要求知识点思路代码 73. 矩阵置零题目链接标签简单版思路代码 优化版思路代码 105. 从前序与中序遍历序列构造二叉树题目链接标签思路代码 196. 删除重复的电子邮箱 题目链接 196. 删除重复的电子邮箱 表 表Person的字段为id和email…

昇思MindSpore学习总结七——模型训练

1、模型训练 模型训练一般分为四个步骤&#xff1a; 构建数据集。定义神经网络模型。定义超参、损失函数及优化器。输入数据集进行训练与评估。 现在我们有了数据集和模型后&#xff0c;可以进行模型的训练与评估。 2、构建数据集 首先从数据集 Dataset加载代码&#xff0…

在windows上安装objection

安装命令pip install objection -i https://mirrors.aliyun.com/pypi/simple hook指定进程 objection -g 测试 explore 进程名不定是包名&#xff0c;也可能是app名字&#xff0c;如“测试”就是app的名字 若出现如下错误&#xff0c;说明python 缺少setuptools 直接安装setu…

秋招突击——设计模式补充——单例模式、依赖倒转原则、工厂方法模式

文章目录 引言正文依赖倒转原则工厂方法模式工厂模式的实现简单工厂和工厂方法的对比 抽线工厂模式最基本的数据访问程序使用工厂模式实现数据库的访问使用抽象工厂模式的数据访问程序抽象工厂模式的优点和缺点使用反射抽象工厂的数据访问程序使用反射配置文件实现数据访问程序…

检索增强生成RAG系列6--RAG提升之查询结构化(Query Construction)

系列5中讲到会讲解3个方面RAG的提升&#xff0c;它们可能与RAG的准确率有关系&#xff0c;但是更多的它们是有其它用途。本期来讲解第二部分&#xff1a;查询结构化&#xff08;Query Construction&#xff09;。在系列3文档处理中&#xff0c;我们着重讲解了文档解析&#xff…

能保存到相册的风景视频在哪下载?下载风景视频网站分享

在当今以视觉为核心的时代&#xff0c;高清美丽的风景视频不仅能够丰富我们的日常生活&#xff0c;还能提供心灵上的慰藉。无论是为了制作视频项目&#xff0c;还是仅仅想要珍藏一些精美的风景画面&#xff0c;获取高质量的风景视频素材显得尤为重要。许多人可能会问&#xff1…

PTrade量化软件常见问题整理系列2

一、研究界面使用get_fundamentals函数报错&#xff1a;error_info:获取token失败&#xff1f; 研究界面使用get_fundamentals函数报错&#xff1a;error_info:获取token失败&#xff1f; 1、测试版本202202.01.052&#xff0c;升级202202.01.051版本后&#xff0c;为了解决不…

在虚拟仿真中学习人工智能,可以达到什么目标?

人工智能已经成为引领社会创新的关键力量&#xff0c;想要在这个充满机遇的领域中脱颖而出&#xff0c;掌握扎实的专业技能和积累丰富的实践经验至关重要。然而&#xff0c;许多学习者在追求这一目标的过程中面临着几个主要问题&#xff1a;专业技术掌握有难度、实践经验积累存…

linux中awk,sed, grep使用

《linux私房菜》这本书中将sed和awk一同归为行的修改这一点&#xff0c;虽然对&#xff0c;但不利于实际处理问题时的思考。因为这样的话&#xff0c;当我们实际处理问题时&#xff0c;遇到比如说统计文本打印内容时&#xff0c;我们选择sed还是awk进行处理呢&#xff1f; 也因…

​香橙派AIpro测评:usb鱼眼摄像头的Camera图像获取

一、前言 近期收到了一块受到业界人士关注的开发板"香橙派AIpro",因为这块板子具有极高的性价比&#xff0c;同时还可以兼容ubuntu、安卓等多种操作系统&#xff0c;今天博主便要在一块832g的香橙派AI香橙派AIpro进行YoloV5s算法的部署并使用一个外接的鱼眼USB摄像头…

React 中如何使用 Monaco

Monaco 是微软开源的一个编辑器&#xff0c;VSCode 也是基于 Monaco 进行开发的。如果在 React 中如何使用 Monaco&#xff0c;本文将介绍如何在 React 中引入 Monaco。 安装 React 依赖 yarn add react-app-rewired --dev yarn add monaco-editor-webpack-plugin --dev yarn…

学习和发展人工智能:新兴趋势和成功秘诀

人工智能(AI)继续吸引组织&#xff0c;因为它似乎无穷无尽地提高生产力和业务成果。在本博客中&#xff0c;了解学习和发展(L&D)部门如何利用人工智能改进流程&#xff0c;简化工作流程&#xff1f; 学习与发展(L&D)部门领导开始探索如何提高和支持人工智能能力的劳动…

1-认识网络爬虫

1.什么是网络爬虫 ​ 网络爬虫&#xff08;Web Crawler&#xff09;又称网络蜘蛛、网络机器人&#xff0c;它是一种按照一定规则&#xff0c;自动浏览万维网的程序或脚本。通俗地讲&#xff0c;网络爬虫就是一个模拟真人浏览万维网行为的程序&#xff0c;这个程序可以代替真人…

工业智能网关在现代工业生产中的重要性-天拓四方

工业智能网关是一款具备挖掘工业设备数据并接入到自主开发的云平台的智能嵌入式网络设备。它具备数据采集、协议解析、边缘计算&#xff0c;以及4G/5G/WiFi数据传输等功能&#xff0c;并能接入工业云平台。这种网关不仅支持采集PLC、传感器、仪器仪表和各种控制器&#xff0c;还…