深入理解指针2

news2025/1/16 8:06:02

各位小伙伴们,我们继续来学习指针,指针和结构体以及动态内存管理对后面的数据结构学习有非常大的帮助,所有我们一定要把这些知识点学会。OK,正式进入学习之旅吧

1.数组名的理解

在上⼀个章节我们在使⽤指针访问数组的内容时,有这样的代码:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = &arr[0];
这⾥我们使⽤ &arr[0] 的⽅式拿到了数组第⼀个元素的地址,但是其实数组名本来就是地址,而且
是数组⾸元素的地址,我们可以来做个测试。
int main()
{
	int arr[10] = { 0 };
	printf("%p\n", &arr[0]);
	printf("%p\n", arr);

	return 0;
}

我们发现数组名和数组⾸元素的地址打印出的结果⼀模⼀样,数组名就是数组⾸元素(第⼀个元素)的地址。
但是如果数组名是首元素的地址的话,那么我们可以看一看下面这个代码输出结果是什么?
int main()
{
 int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
 printf("%d\n", sizeof(arr));
 return 0;
}
输出的结果是:40,如果arr是数组⾸元素的地址,那输出应该的应该是4/8才对。其实数组名是首元素的地址这句话是对的,但是有2个例外:

1.sizeof(数组名),sizeof中单独放数组名,这⾥的数组名表示整个数组,计算的是整个数组的大小,单位是字节。

2.&数组名,这⾥的数组名表示整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素的地址是有区别的)。​​​​​​​

除此之外,任何地方使用数组名,数组名都表示首元素的地址。
我们继续试一试下面这个代码
int main()
{
 int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
 printf("&arr[0] = %p\n", &arr[0]);
 printf("arr = %p\n", arr);
 printf("&arr = %p\n", &arr);
 return 0;
}

奇怪的是三个代码的结果一模一样,那么arr和&arr区别在哪?

我们可以看一下这段代码,就知道数组首元素的地址和整个数组的地址到底是怎么回事了

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	printf("&arr[0]   = %p\n", &arr[0]);
	printf("&arr[0]+1 = %p\n", &arr[0]+1);

	printf("arr       = %p\n", arr);
	printf("arr+1     = %p\n", arr+1);

	printf("&arr      = %p\n", &arr);
	printf("&arr+1    = %p\n", &arr+1);

	return 0;
}

这⾥我们发现&arr[0]和&arr[0]+1相差4个字节,arr和arr+1 相差4个字节,是因为&arr[0] 和 arr 都是⾸元素的地址,+1就是跳过⼀个元素。
但是&arr 和 &arr+1相差40个字节,这就是因为&arr是数组的地址,+1 操作是跳过整个数组的。
到这⾥大家应该搞清楚数组名的意义了吧。

2.使用指针访问数组

有了前⾯知识的支持,再结合数组的特点,我们就可以很方便的使⽤指针访问数组了。
int main()
{
	int arr[10] = { 0 };
	int sz = sizeof(arr) / sizeof(arr[0]);
	int* p = arr;
	int i = 0;
	for (int i = 0; i < sz; i++)
	{
		scanf("%d", p + i);
        //scanf("%d", arr+i);//也可以这样写
	}
	for (i = 0; i < sz; i++)
	{
		printf("%d ", *(p + i));
	}
	return 0;
}

这个代码搞明白后,我们再试⼀下,如果我们再分析⼀下,数组名arr是数组⾸元素的地址,可以赋值给p,其实数组名arr和p在这⾥是等价的。那我们可以使⽤arr[i]可以访问数组的元素,那p[i]是否也可以访问数组呢?答案是可以的。 我们只需要将打印的代码*(p+i)换成p[i]也是能够正常打印的,所以本质上p[i] 是等价于 *(p+i)。
同理arr[i] 应该等价于 *(arr+i),数组元素的访问在编译器处理的时候,也是转换成⾸元素的地址+偏移量求出元素的地址,然后解引⽤来访问的。
因为加法支持交换律,所以还能写成这样”i[arr]“,*(i+arr)等价于i[arr]。不过这种写法不常用,小伙伴们还是用自己习惯的方式来写。

3.一维数组传参的本质

数组我们学过了,之前也讲了,数组是可以传递给函数的,这个小节我们讨论⼀下数组传参的本质。⾸先从⼀个问题开始,我们之前都是在函数外部计算数组的元素个数,那我们可以把数组传给⼀个函数后,函数内部求数组的元素个数吗?我们可以先想一个下面这段代码的结果是什么。
void test(int arr[])
{
	int sz = sizeof(arr) / sizeof(arr[0]);
	printf("%d", sz);
}

int main()
{
	int arr[10] = { 0 };
	test(arr);
	return 0;
}

结果是1,这是因为数组传参的时候,传递的并非是数组,而是是首元素的地址,传地址要用指针来接收。在x86环境下,int类型的指针变量大小是4个字节,一个元素的大小是4,所以结果是1。

也就是说本质上数组传参本质上传递的是数组首元素的地址。
函数形参的部分理论上应该使⽤指针变量来接收⾸元素的地址。那么在函数内部我们写sizeof(arr) 计算的是⼀个地址的大小(单位字节)⽽不是数组的大小(单位字节)。正是因为函数的参数部分是本质是指针,所以在函数内部是没办法求的数组元素个数的。
总之一句话:⼀维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。

 4.二级指针

指针变量也是变量,是变量就有地址,那指针变量的地址存放在哪⾥?所以接下来我们要学习二级指针。

 

对于⼆级指针的运算有:
*pp 通过对pp中的地址进⾏解引⽤,这样找到的是 p *pp  其实访问的就是 p。
**pp 先通过 *pp  找到 ,然后对 进⾏解引⽤操作: *p  ,那找到的是 a。

5.指针数组

指针数组是指针还是数组?
我们类比⼀下,整型数组:是存放整型的数组;字符数组:是存放字符的数组。
那指针数组呢?是存放指针的数组。这样写是不是比较好理解了。如图所示
那么指针数组到底有什么用呢?接下来我们通过一段代码来看一下有什么用

6.指针数组模拟二维数组

值得注意的是实际上并非完全是⼆维数组,因为每⼀行并非是连续的。

int main()
{
	int arr1[] = { 1,2,3,4,5 };
	int arr2[] = { 2,3,4,5,6 };
	int arr3[] = { 3,4,5,6,7 };

	int* arr[3] = { arr1,arr2,arr3 };

	int i = 0;
	for (i = 0; i < 3; i++)
	{
		int j = 0;
		for (j = 0; j < 5; j++)
		{
			printf("%d ", arr[i][j]);
		}
		printf("\n");
	}
	return 0;
}

arr[i]是访问arr数组的元素,arr[i]找到的数组元素指向了整型⼀维数组,arr[i][j]就是整型⼀维数组中的元素。
OK,今天指针内容的学习就到这里了,还有一部分指针的内容我们以后在学,小伙伴们一定要把今天的知识点吃透,我们再接再励。

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

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

相关文章

【RN】学习使用 Reactive Native内置UI组件

简言 当把导航处理好后&#xff0c;就可以学习使用ui组件了&#xff08;两者没有先后关系&#xff0c;个人习惯&#xff09;。 在 Android 和 iOS 开发中&#xff0c;一个视图是 UI 的基本组成部分&#xff1a;屏幕上的一个小矩形元素、可用于显示文本、图像或响应用户输入。甚…

300分钟吃透分布式缓存-14讲:大数据时代,MC如何应对新的常见问题?

大数据时代 Memcached 经典问题 随着互联网的快速发展和普及&#xff0c;人类进入了大数据时代。在大数据时代&#xff0c;移动设备全面融入了人们的工作和生活&#xff0c;各种数据以前所未有的 速度被生产、挖掘和消费。移动互联网系统也不断演进和发展&#xff0c;存储、计…

低代码与大语言模型的探索实践

低代码系列文章&#xff1a; 可视化拖拽组件库一些技术要点原理分析可视化拖拽组件库一些技术要点原理分析&#xff08;二&#xff09;可视化拖拽组件库一些技术要点原理分析&#xff08;三&#xff09;可视化拖拽组件库一些技术要点原理分析&#xff08;四&#xff09;低代码…

推荐系统经典模型YouTubeDNN

文章目录 YouTubeDNN概念YouTubeDNN模型架构图YouTubeDNN召回阶段YouTubeDNN层级介绍 YouTubeDNN排序阶段YoutubeDNN模型中的一些Trick负采样问题特征构造上下文选择 总结 YouTubeDNN概念 YouTubeDNN是YouTube用于做视频推荐的落地模型&#xff0c;其大体思路就是召回阶段使用…

【MySQL面试复习】什么是聚簇索引(聚集索引)和非聚簇索引(二级索引)/什么是回表?

系列文章目录 在MySQL中&#xff0c;如何定位慢查询&#xff1f; 发现了某个SQL语句执行很慢&#xff0c;如何进行分析&#xff1f; 了解过索引吗&#xff1f;(索引的底层原理)/B 树和B树的区别是什么&#xff1f; 系列文章目录什么是聚簇索引&#xff08;聚集索引&#xff09…

逆向茶话会笔记

安卓逆向 用用burp设置代理或者用charles抓包 windows httpopen 类比web站点渗透测试 推荐书 飞虫 安卓大佬不怎么打ctf 喜欢在看雪和吾爱破解 提问环节 q websocket grpc抓包有什么推荐的工具&#xff1f; a 不太了解 游戏安全和llvm 既要逆游戏也要逆外挂 逆游戏入…

分布式知识整理

分布式锁 以商场系统超卖现象举例 超卖现象一 现象&#xff1a; 商品卖出数量超出了库存数量。 产生原因&#xff1a; 扣减库存的动作在程序中进行&#xff0c;在程序中计算剩余库存&#xff0c;在并发场景下&#xff0c;导致库存计算错误。 代码复现 es.shutdown(); cycl…

笔记本hp6930p安装Android-x86避坑日记

一、序言 农历癸卯年前大扫除&#xff0c;翻出老机hp6930p&#xff0c;闲来无事&#xff0c;便安装Android-x86玩玩&#xff0c;期间多次入坑&#xff0c;随手记之以避坑。 笔记本配置&#xff1a;T9600,4G内存&#xff0c;120G固态160G机械硬盘 二、Android-x86系统简介 官…

第二节:Vben Admin 登录逻辑梳理和对接后端准备

系列文章目录 上一节&#xff1a;第一节&#xff1a;Vben Admin介绍和初次运行 文章目录 系列文章目录前言项目路径的概述一、登录逻辑梳理loginApi接口查看Mock 二、后端程序对接准备关闭Mock 总结 前言 第一节&#xff0c;我们已经配置了前端环境&#xff0c;运行起来了我们…

vue基础操作(vue基础)

想到多少写多少把&#xff0c;其他的想起来了在写。也写了一些css的 input框的双向数据绑定 html <input value"123456" type"text" v-model"account" input"accou" class"bottom-line bottom" placeholder"请输入…

数据库安全性与完整性设计

文章标签集合[数据库安全,数据敏感,通信安全,MD5,盐加密] 1 系统设计 1.1设计目标 &#xff08;1&#xff09;确定系统中需要保护的敏感数据和通信内容&#xff1b; &#xff08;2&#xff09;设计合适的签名、加密和解密算法&#xff1b; &#xff08;3&#xff09;实现…

遗传算法(Genetic Algorithm,GA)求解不闭合多旅行商问题(提供MATLAB代码)

一、遗传算法&#xff08;GA&#xff09;介绍 遗传算法&#xff08;Genetic Algorithm&#xff0c;GA&#xff09;是一种模拟自然界生物进化过程的优化算法。它通过模拟生物的遗传、变异和选择等机制&#xff0c;来搜索问题的最优解。 遗传算法的基本思想是通过对候选解进行编…

matlab绘制雷达图和二维FFT变换图

1、内容简介 略 49-可以交流、咨询、答疑 matlab绘制雷达图和二维FFT变换图 NMO组及NORMAL组 RNFL层、GCL层、IPL层、GCC层、ORL层做雷达图&#xff08;共10张&#xff09; 2、内容说明 略 NMO组及NORMAL组 RNFL层、GCL层、IPL层、GCC层、ORL层请分别做雷达图&#xff08…

CAS5.3使用JPA实现动态注册服务

cas同时支持cas协议和OAuth2协议,官方默认是通过扫描json文件的形式注册客户端服务,但是此种方式需要重启服务才能生效,此次我们将使用JPA来完美实现动态注册服务,如果不知道cas如何部署,可以擦看之前的文章 cas-client基于CAS协议客户端搭建-CSDN博客 cas-server5.3自定义密…

Vue 卸载eslint

卸载依赖 npm uninstall eslint --save 然后 进入package.json中&#xff0c;删除残留信息。 否则在执行卸载后&#xff0c;运行会报错。 之后再起项目。

HTTPS对HTTP的加密过程

1、HTTPS是在HTTP的基础上&#xff0c;引入了一个加密层&#xff08;SSL&#xff09;&#xff0c;对数据进行保护&#xff0c;HTTP 是明文传输的&#xff08;不安全&#xff0c;很可能会被运营商通过referer劫持&#xff0c;或者黑客通过修改链接来窃数据&#xff09; 2、加密…

Typora结合PicGo + 使用Github搭建个人免费图床

文章目录 一、国内图床比较二、使用Github搭建图床三、PicGo整合Github图床1、下载并安装PicGo2、设置图床3、整合jsDelivr具体配置介绍 4、测试5、附录 四、Typora整合PicGo实现自动上传 每次写博客时&#xff0c;我都会习惯在Typora写好&#xff0c;然后再复制粘贴到对应的网…

redis数据结构源码分析——压缩列表ziplist(I)

前面讲了跳表的源码分析&#xff0c;本篇我们来聊一聊另外一个重点结构——压缩列表 文章目录 存储结构字节数组结构节点结构 压缩编码zipEntryzlEntry ZIP_DECODE_PREVLENZIP_DECODE_LENGTH API解析ziplistNew(创建压缩列表)ziplistInsert(插入)ziplistDelete(删除)ziplistFi…

.NET Core使用NPOI导出复杂,美观的Excel详解

前言&#xff1a; 这段时间一直专注于数据报表的开发&#xff0c;当然涉及到相关报表的开发数据导出肯定是一个不可避免的问题啦。客户要求要导出优雅&#xff0c;美观的Excel文档格式的来展示数据&#xff0c;当时的第一想法就是使用NPOI开源库来做数据导出Excel文档&#xf…

第四节:Vben Admin登录对接后端getUserInfo接口

系列文章目录 第一节&#xff1a;Vben Admin介绍和初次运行 第二节&#xff1a;Vben Admin 登录逻辑梳理和对接后端准备 第三节&#xff1a;Vben Admin登录对接后端login接口 第四节&#xff1a;Vben Admin登录对接后端getUserInfo接口 文章目录 系列文章目录前言一、回顾Vben…