对(一维)数组与指针的深入理解(1)

目录

  • 1.数组名的理解
  • 2.使用指针访问(一维)数组
  • 3.(一维)数组传参的本质

1.数组名的理解

以前我们在使用指针访问数组内容时,有这样的代码:

#include <stdio.h>int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int* p = &arr[0];
}

这里我们使用 &arr[0] 的方式拿到了数组第一个元素的地址,但是数组名本身就是首元素地址,我们来进行测试:

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

输出结果:

在这里插入图片描述

我们发现数组名和数组首元素的地址打印出来一模一样,数组名就是数组首元素(第一个元素)的地址。

那么下面的代码会让大家产生疑惑:

#include <stdio.h>int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("%zd\n",sizeof(arr));return 0;
}

输出结果:

在这里插入图片描述

如果arr是首元素地址,那么在32位/64位平台下的地址大小应该是4/8个字节,但是这里是40个字节,这又该怎么解释呢?

其实数组名就是首元素地址是对的,但是有两个例外:

  • sizeof(数组名)
    sizeof中单独放数组名,这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节。
  • &数组名
    这里的数组名表示的是整个数组,取出的是整个数组的地址(整个数组的地址和数组首元素地址是有区别的)

除上述两种情况外,任何地方使用数组名,数组名都表示首元素地址

我们再试一下这个代码:

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 加1都相差4个字节,是因为&arr[0]和arr都是首元素地址,+1就是跳过一个元素,这里的元素是整型。

但是&arr和&arr+1相差了40个字节,这就是因为&arr是整个数组的地址,+1跳过的是整个数组。

画图演示:

在这里插入图片描述
这样我们就理解了arr与&arr的区别。

2.使用指针访问(一维)数组

有了前面的知识以及数组的特点,我们就可以使用指针访问数组了。

我们能够使用指针访问数组主要基于以下两个原因:

  1. 数组在内存中是连续存放的。
  2. 指针±整数运算,方便我们获得每一个元素的地址
int main()
{int arr[10] = { 0 };//使用指针来访问数组int sz = sizeof(arr) / sizeof(arr[0]);//输入10个值int* p = arr;int i = 0;for (i = 0; i < sz; i++){//输入一个值scanf("%d", p + i);// p+i == &arr[i]}//输出10个值for (i = 0; i < sz; i++){printf("%d ", *(p + i));}return 0;
}

输出结果:

在这里插入图片描述

其实上述代码中的第13行与第19行可以进行变更修改:

在这里插入图片描述

这里由读者自行写代码试验。

3.(一维)数组传参的本质

要讨论(一维)数组传参的本质,我们可以先从一个问题开始,我们之前都是在函数外部计算数组的元素个数,那我们可以把数组传给一个函数后,在函数内部求数组的元素个数吗?

代码1:在函数外求元素个数

void print(int arr[], int sz)
{int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}
}int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);print(arr, sz);return 0;
}

输出结果:

在这里插入图片描述

代码2:在函数内求元素个数

void print(int arr[])
{int sz = sizeof(arr) / sizeof(arr[0]);int i = 0;for (i = 0; i < sz; i++){printf("%d ", arr[i]);}
}int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };print(arr);return 0;
}

输出结果:

在这里插入图片描述

从输出结果我们可以知道,在函数内外计算元素个数的两个程序运行的结果不同,代码2明显与我们的预期结果不相符,这是为什么呢?

要检查哪里出了问题,我们可以对代码2进行调试:

在这里插入图片描述

经过调试,我们发现了当程序执行到print函数计算sz时,结果并不是数组的元素个数10,而是1,所以for循环只执行一次,打印输出结果为1。

为什么sz=1呢?这是我们要思考的地方。

原因是因为主函数中print(arr)中的arr数组名就是数组首元素的地址,当我们实参传入arr时,实参本质上是用指针变量接收的,所以print函数我们也可以定义成:

void print (int * p)//这里应该是指针
{}

所以数组传参的时候,形参是可以写成数组形式的,但是本质上还是指针变量
所以代码2中sizeof(arr)实际上计算的是一个指针变量的大小,在x86环境下大小为4,而一个元素的大小也是4,所以相除得sz=1。

综上所述,我们可以知道:

  1. 数组传参的本质是传递了数组首元素的地址,所以形参访问的数组和实参的数组是同一个数组。
  2. 形参的数组是不会单独再创建数组空间的,所以形参的数组可以省略掉数组的大小。

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

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

相关文章

详解Qt多线程(包含:什么是CPU,单核处理器和多核处理器,举餐厅和QQ音乐的例子详解进程和线程,Qt多线程案例)

目录 一.什么是CPU&#xff1f;二.单核处理器与多核处理器三.什么是进程和线程&#xff1f;3.1 定义3.2 以餐厅为例子解释进程和线程3.2 以QQ音乐为例子&#xff0c;解释QQ音乐里面的进程和线程 四.Qt中的多线程五.Qt多线程案例任务描述案例演示设置显示内容的字体大小和位置运…

pands常用操作

1.导入库和文件读取和文件分信息分析 import pandas as pd import numpy as np csvf pd.read_csv(D:/各个站程序版本说明.csv) csvf.info() <class pandas.core.frame.DataFrame> RangeIndex: 51 entries, 0 to 50 Data columns (total 6 columns):# Column Non-Nul…

java面试题整理

2023.2.14&#xff08;第二天&#xff09; 数组是不是对象&#xff1f; 在Java中&#xff0c;数组是对象。数组是一种引用类型&#xff0c;它可以存储固定大小的相同类型的元素序列。在Java中&#xff0c;数组是通过new关键字创建的&#xff0c;它们在内存中被分配为对象&…

「数据结构」MapSet

&#x1f387;个人主页&#xff1a;Ice_Sugar_7 &#x1f387;所属专栏&#xff1a;Java数据结构 &#x1f387;欢迎点赞收藏加关注哦&#xff01; Map&Set &#x1f349;概念&#x1f349;模型&#x1f349;Map&#x1f34c;TreeMap和HashMap的区别&#x1f34c;Map常用方…

2048游戏C++板来啦!

个人主页&#xff1a;PingdiGuo_guo 收录专栏&#xff1a;C干货专栏 大家好呀&#xff0c;我是PingdiGuo_guo&#xff0c;今天我们来学习如何用C编写一个2048小游戏。 文章目录 1.2048的规则 2.步骤实现 2.1: 初始化游戏界面 2.1.1知识点 2.1.2: 创建游戏界面 2.2: 随机…

Days 31 ElfBoard 自启脚本中打开看门狗

1.在开机自启脚本中打开看门狗 rootELF1:~# vi /etc/rc.local 2.在自启脚本中添加上之后&#xff0c;然后在咱们的QT界面中找到看门狗应用&#xff0c; 发现显示打开看门狗失败&#xff1a; 3.修改看门狗源码&#xff0c;设置了超时时间后&#xff0c;关闭/dev/dev/watchdog节…

【Tomcat】:One or more listeners failed to start.报错解决方案

报错信息:One or more listeners failed to start. Full details will be found in the appropriate container log file. 具体就是web.xml此配置报错: 服务器启动错误Tomcat:One or more listeners failed to start.报错解决方案 IDEA:在使用IDEA运行SSM项目的时候 , Tomcat运…

error MSB8008: 指定的平台工具集(v143)未安装或无效。请确保选择受支持的 PlatformToolset 值解决办法

右击解决方案&#xff0c;选择属性 将工具集为143的修改为其他&#xff0c;如图 重新编译即可运行

网络原理(3)--以太网协议,DNS

&#x1f495;"Echo"&#x1f495; 作者&#xff1a;Mylvzi 文章主要内容&#xff1a;网络原理(3)–以太网协议,DNS 在网络原理(2)中介绍了网络层中的一个重要的协议–ip协议,网络层关注的通信时的起点和终点,而数据链路层更加"底层"一些,关注的是传输过程…

【Effective Objective - C 2.0】——读书笔记(四)

文章目录 二十三、通过委托与数据源协议进行对象间通信二十四、将类的实现代码分散到便于管理的数个分类之中二十五、总是为第三方的分类名称加前缀二十六、切勿在分类里面声明属性二十七、使用“class-continuation分类”隐藏实现细节二十八、通过协议提供匿名对象 二十三、通…

springboot187社区养老服务平台的设计与实现

简介 【毕设源码推荐 javaweb 项目】基于springbootvue 的 适用于计算机类毕业设计&#xff0c;课程设计参考与学习用途。仅供学习参考&#xff0c; 不得用于商业或者非法用途&#xff0c;否则&#xff0c;一切后果请用户自负。 看运行截图看 第五章 第四章 获取资料方式 **项…

MySQL 基础知识(六)之数据查询(一)

目录 1 基本查询 1.1 查询相关列 (select * / 列名) 1.2 别名 (as) 1.3 去重 (distinct) 1.4 对列中的数据进行运算 (、-、*、/) 2 条件查询 (where) 2.1 等值查询 () 2.2 非等值查询 (>、<、>、<、!、><) 2.3 逻辑判断 (and、or、not) 2.4 区间判…

源码推荐:hello-algo @ github

github https://github.com/krahets/hello-algo 本项目旨在创建一本开源、免费、对新手友好的数据结构与算法入门教程。全书采用动画图解&#xff0c;结构化地讲解数据结构与算法知识&#xff0c;内容清晰易懂&#xff0c;学习曲线平滑。算法源代码皆可一键运行&#xff0c;支…

上位机图像处理和嵌入式模块部署(借鉴与学习)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 对于很多学院派的同学来说&#xff0c;他们对市场的感觉一般是比较弱的。如果写一个软件的话&#xff0c;或者说开发一个项目的话&#xff0c;他们…

(一)【Jmeter】JDK及Jmeter的安装部署及简单配置

JDK的安装和环境变量配置 对于Linux、Mac和Windows系统&#xff0c;JDK的安装和环境变量配置方法略有不同。以下是针对这三种系统的详细步骤&#xff1a; 对于Linux系统&#xff1a; 下载适合Linux系统的JDK安装包&#xff0c;可以选择32位或64位的版本。 将JDK的安装包放置…

VueCLI核心知识3:全局事件总线、消息订阅与发布

这两种方式都可以实现任意两个组件之间的通信 1 全局事件总线 1.安装全局事件总线 import Vue from vue import App from ./App.vueVue.config.productionTip false/* 1.第一种写法 */ // const Demo Vue.extend({}) // const d new Demo()// Vue.prototype.x d // 把Dem…

RK3568平台开发系列讲解(实验篇)用户空间和内核空间数据交换

🚀返回专栏总目录 文章目录 一、用户空间和内核空间数据交换二、实验驱动代码三、应用测试代码沉淀、分享、成长,让自己和他人都能有所收获!😄 一、用户空间和内核空间数据交换 内核空间和用户空间的内存是不能互相访问的。但是很多应用程序都需要和内核进行数据的交换,…

【AI视野·今日NLP 自然语言处理论文速览 第七十八期】Wed, 17 Jan 2024

AI视野今日CS.NLP 自然语言处理论文速览 Wed, 17 Jan 2024 (showing first 100 of 163 entries) Totally 100 papers &#x1f449;上期速览✈更多精彩请移步主页 Daily Computation and Language Papers Deductive Closure Training of Language Models for Coherence, Accur…

优化策略模式,提高账薄显示的灵活性和扩展性

接着上一篇文章&#xff0c;账薄显示出来之后&#xff0c;为了提高软件的可扩展性和灵活性&#xff0c;我们应用策略设计模式。这不仅仅是为了提高代码的维护性&#xff0c;而是因为明细分类账账薄显示的后面有金额分析这个功能&#xff0c;从数据库后台分析及结合Java语言特性…

2024幻兽帕鲁服务器创建教程_阿里PK腾讯超简单

幻兽帕鲁官方服务器不稳定&#xff1f;自己搭建幻兽帕鲁服务器&#xff0c;低延迟、稳定不卡&#xff0c;目前阿里云和腾讯云均推出幻兽帕鲁专用服务器&#xff0c;腾讯云直接提供幻兽帕鲁镜像系统&#xff0c;阿里云通过计算巢服务&#xff0c;均可以一键部署&#xff0c;鼠标…