数组传参不理解?(数组传参的本质)

news2024/11/17 21:24:56

       在我们编写程序时,经常需要传递参数给函数,其中一种常见的参数类型就是数组。数组作为一种数据结构,可以存储多个相同类型的数据元素,并按照一定的顺序排列。在函数中传递数组参数,可以方便地对数组进行操作处理。但是,数组传参也有其特殊和需要注意的地方。在文中,我将向大家讲解数组作为参数传递时的一些问题和解决方法。学习之前我们要先了解数组的一些基础知识,也是对前期数组知识的补充。

一维数组与二维数组

本文将重点针对对一维数组和二维数组进行讲解。

前几期中我对一维数组的创建及初始化已进行了讲解,先对二维数组进行简单介绍。

二维数组

二维数组我们可以理解为一个数组里放了多个一维数组

例如:arr[4][5]:可以理解为arr[4][5]中存放了四个数组,分别名为arr[0],arr[1],arr[2],arr[3]每个数组大小都是5;

arr[0]:arr[0][0],arr[0][1],arr[0][2],arr[0][3],arr[0][4]

arr[1]:arr[1][0],arr[1][1],arr[1][2],arr[1][3],arr[1][4]

arr[2]:arr[2][0],arr[2][1],arr[2][2],arr[2][3],arr[2][4]

arr[3]:arr[3][0],arr[3][1],arr[3][2],arr[3][3],arr[3][4]

二维数组和一维数组在内存中存储都是连续存放的。

首先我们先写一个小程序对二维数组进行初始化

#include<stdio.h>
int main() {
    int arr[2][3];
    int i = 0;
    for (i = 0; i < 2; i++) {
        for (int j = 0; j < 3; j++) {
            scanf("%d", &arr[i][j]);
        }
    }
    for (i = 0; i < 2; i++) {
        int j = 0;
        for (j = 0; j < 3; j++) {
            printf("%d ", arr[i][j]);
        }
        printf("\n");
    }
    return 0;
}

 通过调试时我们可以发现相邻的两个元素之间地址相差4(这里表示地址使用的是16进制,每个元素相差4个字节),并且是连续的。随着数组下标的增长,元素的地址也在有规律的增长(由低地址到高地址)。

 二维数组的创建

二维数组的创建与一维数组很相似,当然我们也可以创建多种类型的数组

char arr[2][3];
int arr1[3][4];
double arr2[2][4];

二维数组的初始化

有以下几种初始化形式。

int arr[3][4]={1,2,3,4};
int arr1[3][4]={{1,2},{3,4}};
int arr2[][4]={{2,3},{4,5}};

二维数组的两个[],分别代表的是行和列,前两个数组创建时是一个三行四列的数组,并且在数据元素不够时,会进行补0操作。

注意:二维数组的行可以省,但列不行,计算机会根据初始化时的数据自动计算行的值,而对于列,规定列的大小是为了确定后续计算机进行补0的个数。

数组越界

数组的下标是有范围的。

数组下标规定从0开始,如果数组有n个元素,那么最后一个数组下标就是n-1。

所以数组下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。

C语言本身是不做数组下标的越界检查,编译器也不一定会报错,但编译器不报错就并不意味着程序就是正确的。

所以在写代码时,程序员最好自己做越界检查。

 

 如上图,编译器没有报错,最后一个数字因为数组越界访问输出结果是随机值。

当然二维数组的行和列也可能存在越界访问

数组作为函数参数

在写代码时,会将数组作为参数传给函数,比如:实现一个冒泡排序的函数

先解释一下冒泡排序的原理以升序为例:相邻两个数字进行比较,较大数与后一个数位置交换

 

 最终直到最大数到最后的位置(此过程需要比较9次)

 

 这个过程为一趟,而第二趟就只需要交换8次,第三趟需要交换7次,需要交换的次数依次减少,一共需要9趟(交换次数也就是9!)由于我示例数据是降序,要排列为升序,需要交换的次数是最多的,在乱序数据中,交换次数只会比示例交换次数少。

代码实现:

for (int j = 0; j < sz-1; j++) //sz是数组元素个数
	{
		for (int i = 0; j < sz - 1 - i; i++) 
		{
			if (arr[i] > arr[i + 1]) 
			{
				t = arr[i];   //t是作为交换的中间媒介
				arr[i] = arr[i + 1];
				arr[i + 1] = t;
			}
		}
	}

写一个冒泡排序函数该如何实现呢?

void bubble(int arr[10]) {
	int t;
    int sz = sizeof(arr) / sizeof(arr[0]);//计算数组元素个数

	for (int j = 0; j < sz-1; j++) 
	{
		for (int i = 0; j < sz - 1 - i; i++) 
		{
			if (arr[i] > arr[i + 1]) 
			{
				t = arr[i];
				arr[i] = arr[i + 1];
				arr[i + 1] = t;
			}
		}
	}
}

int main()
 {
	int arr[10];

	for (int i = 0; i < 10; i++) {
		scanf("%d", &arr[i]);
	}

bubble(arr);

	for (int i = 0; i < 10; i++) {
		printf("%d ", arr[i]);
	}

	return 0;
}

这段代码可以实现冒泡排序吗?当结果运行起来我们会发现,结果并没有预期那样排序,这是为什么呢?

在调用函数时bubble(arr),arr作为数组进行传参,数组传参,传递的实质是首元素的地址,而void bubble(int arr[10])这里的arr[10]本质上也是指针,在函数中我们使用sizeof计算数组大小也仅仅只是形参接收的首元素地址。

 通过调试我们会发现这里的sz的值是1(在64位操作系统结果是2,64位操作系统中,指针变量占8个字节除以arr[0]整形所以结果是2)。

或许有同学会疑惑arr是数组首元素地址那sizeof(arr)为什么就可以计算数组长度。

这里额外补充一下

数组名的理解

数组名该怎么理解?

在通常情况下数组名就是首元素的地址。但是有两个意外

1.sizeof(数组名),数组名单独放在sizeof()内部,这里的数组名表示整个数组,计算的是数组大小

2.&数组名,这里的数组名也是表示整个数组,取出的是整个数组的地址

除此之外所有遇到的数组名都表示数组首元素的地址。

 这里通过代码给大家更清晰的呈现:

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9 };//%p用来打印地址
	printf("%p\n", arr);
	printf("%p\n", &arr[0]);
	printf("%p\n", &arr);
	printf("%p\n", &arr+1);
	printf("%p\n", arr+1);
	return 0;
}

 运行结果如下:

 我们发现前3个结果相同,这是因为整个数组的地址也是从首元素地址开始的,将&arr+1,和arr+1我们就会发现结果不同。&arr+1结果与首元素地址相差28(这里28是16进制转化为10进制就是40。)正好相差一个数组的大小,arr+1与首元素地址相差4。

区别在于:arr+1跳过的是一个数组元素,而&arr+1跳过的是整个数组。

那如何完成冒泡排序函数呢?

也很简单,只需在主函数里求好数组元素个数,传到函数中(上述情况说明:数组元素是数组时没法在函数中计算大小,这里也仅限数组元素是数字,字符串数组可以),就可以解决这个问题。

代码修改后:

void bubble(int arr[10],int sz) {
	int t;
	
	for (int j = 0; j < sz-1; j++) 
	{
		for (int i = 0; j < sz - 1 - i; i++) 
		{
			if (arr[i] > arr[i + 1]) 
			{
				t = arr[i];
				arr[i] = arr[i + 1];
				arr[i + 1] = t;
			}
		}
	}
}
int main() {
	int arr[10];
	for (int i = 0; i < 10; i++) {
		scanf("%d", &arr[i]);
	}
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble(arr, sz);
	for (int i = 0; i < 10; i++) {
		printf("%d ", arr[i]);
	}
	return 0;
}

这里在给大家补充一点:计算数组元素个数有sizeof(数组名)/sizeof(arr[0]),和strlen(数组名)两种,

char str[]="hello world"
printf("%d %d",sizeof(str),strlen(str));//输出结果是:12 11

sizeof(str):获取数组的总大小,12个元素,每个元素占1个字节,因此总共是12个字节

strlen(str): 获取字符串中有效字符的个数,不算'\0',因此总共11个有效字符。此外strlen是只能计算字符串长度。在函数中可以使用strlen计算字符串数组的大小(当然字符串数组传进去的也是数组首元素地址)。

好了本期内容到这里就结束了,希望对你有所帮助,感谢观看!

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

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

相关文章

StarCoder - 源代码大模型

StarCoder 是一种在源代码和自然语言文本上训练的语言模型 (LM)。 它的训练数据包含 80 多种不同的编程语言以及从 github 问题和提交以及笔记本中提取的文本。 StarCoder 是在 github 代码上训练的&#xff0c;因此它可以用来执行代码生成。 更准确地说&#xff0c;模型可以完…

手术麻醉系统源码——业务流程介绍

采用计算机和通信技术&#xff0c;实现监护仪、麻醉机、呼吸机、输液泵等设备输出数据的自动采集&#xff0c;采集的数据能够如实准确地反映患者生命体征参数的变化&#xff0c;并实现信息高度共享&#xff0c;根据采集结果&#xff0c;综合其他患者数据&#xff0c;自动生成手…

在springboot项目中配置数据库下划线命名映射为java的驼峰命名时出错

问题 在使用spirngboot集成mybaits的时候&#xff0c;想要开启命名映射&#xff0c;如图配置 # mybatis配置 mybatis:type-aliases-package: com.zhong.springcloud.pojoconfig-location: classpath:mybatis/mybatis-config.xmlmapper-locations: classpath:mybatis/mapper/*…

4年外包出来,5次面试全挂....

我的情况 大概介绍一下个人情况&#xff0c;男&#xff0c;毕业于普通二本院校非计算机专业&#xff0c;18年跨专业入行测试&#xff0c;第一份工作在湖南某软件公司&#xff0c;做了接近4年的外包测试工程师&#xff0c;今年年初&#xff0c;感觉自己不能够再这样下去了&…

深入理解二分类和多分类CrossEntropy Loss和Focal Loss

深入理解二分类和多分类CrossEntropy Loss和Focal Loss 二分类交叉熵 在二分的情况下&#xff0c;模型最后需要预测的结果只有两种情况&#xff0c;对于每个类别我们的预测得到的概率为 p p p和 1 − p 1-p 1−p&#xff0c;此时表达式为&#xff08; 的 log ⁡ \log log底数…

如何用ChatGP协助你,从品牌角度对产品提出升级建议?

该场景对应的关键词库&#xff08;19个&#xff09;&#xff1a; 品牌洋葱图思维模型、产品信息、人群、品类、属性、体验、差异化特征、功效、品牌价值主张、目标用户、需求、痛点、爽点、消费者、外观、功能、结构、产品优化建议、产品开发可行性。 提问模板(3个&#xff09…

《Vue.js 设计与实现》—— 01 权衡的艺术

书籍链接&#xff1a;https://weread.qq.com/web/bookDetail/c5c32170813ab7177g0181ae 框架设计里到处都体现了权衡的艺术。 当我们设计一个框架时&#xff0c;框架本身的各个模块之间并不是相互独立的&#xff0c;而是相互关联、相互制约的。 作为框架设计者&#xff0c;一…

Windows10安装免安装版redis

下载 官方下载地址&#xff1a;github.com/MicrosoftAr…选择版本 解压安装 配置环境变量&注册成服务 配置环境变量 以管理员启动命令行&#xff0c;在redis安装根目录&#xff0c;把redis注册服务 redis-server --service-install redis.windows-service.conf --lo…

Communications chemisty|德睿智药工作-用于分子性质预测的药物约束异构图Transformer模型

德睿智药的分子性质预测任务 题目&#xff1a; Pharmacophoric-constrained heterogeneous graph transformer model for molecular property prediction 文献来源&#xff1a;COMMUNICATIONS CHEMISTRY | (2023) 6:60 | 代码&#xff1a;https://github.com/stardj/PharmHG…

springboot+dubbo+zookeeper 项目实战

现在有一段代码再前台&#xff0c;后台系统中都存在&#xff0c;都需要这段代码&#xff0c;存在这种情况&#xff0c;我们可以选择将这段代码提取出来作为一个服务&#xff0c;让前台和后台系统作为消费者远程调用这段代码&#xff0c;提高了代码的复用性。 springboot集成dub…

Unity Audio -- (2)创建动态音效

评估场景需求 本节的目标是添加脚步声到角色身上&#xff0c;当角色走路时&#xff0c;触发动画事件并播放声音。 脚步声是我们在真实世界中常常被我们所忽视的声音&#xff0c;但脚步声能够传达出许多环境信息。你现在可以花一小段时间绕着你周围的环境走一走并仔细听听脚步声…

CLIP : Learning Transferable Visual Models From Natural Language Supervision

CLIP : Learning Transferable Visual Models From Natural Language Supervision IntroductionApproach Introduction 在raw的数据上自监督的训练模型&#xff0c;已经在NLP领域取得了革命性进展&#xff0c;这种模型需要收到硬件、数据的限制&#xff0c;但是能得到很好的迁…

算法 DAY55 动态规划11 392.判断子序列 115.不同的子序列

392.判断子序列 本题可以直接用双指针解法。但是本题是编辑距离的入门题目&#xff0c;故采用动态规划解法为后序“编辑距离”类题目打基础。 本题与最大子序列非常相似&#xff0c;但不同的是s必须连续&#xff0c;t可以不连续。 五部曲 1、dp[i][j] 表示以下标i-1为结尾的字…

Seata介绍

介绍&#xff1a; Seata的设计目标是对这个业务无侵入&#xff0c;因此从业务无侵入的2PC方案开始的&#xff0c;在传统的2PC的基础上演进的。它把一个分布式事务拆分理解成一个包含了若干分支事务的全局事务。全局事务的职责是协调其下管辖的分支事务达成一致性&#xff0c;要…

25.自定义注解

自定义注解 一、什么是注解 Annontation是Java1.5开始引入的新特征&#xff0c;中文名称叫注解。 它提供了一种安全的类似注释的机制&#xff0c;用来将信息或元数据&#xff08;metadata&#xff09;与程序元素&#xff08;类、方法、成员变量等&#xff09;进行关联。为程序…

大数据技术之SparkSQL——数据的读取和保存

一、通用的加载和保存方式 SparkSQL提供了通用的保存数据和数据加载的方式。根据不同的参数读取&#xff0c;并保存不同格式的数据。SparkSQL默认读取和保存的文件格式为Parquet。 1.1 加载数据 spark.read.load 是加载数据的通用方式。 如果读取不同格式的数据&#xff0c;可…

如何编译DPDK静态库

阅读前面文章https://blog.csdn.net/qq_36314864/article/details/130243348,知道了哪些dpdk文件可以在windows下生成。 打开vs,新建一个生成静态库工程,在生成的lib文件中找到D:\dpdk-21.07\build\lib D:\dpdk-21.07\build\drivers找到对应的文件,并按照路径,新建筛选项…

【Vue学习笔记7】Vue3中如何开发组件

重点学习&#xff1a;vue3.0之组件通信机制defineProps&#xff08;组件接收外部传来的参数&#xff09;、defineEmits&#xff08;向组件外部传递参数&#xff09;。 1. 评级组件第一版 简单的评级需求&#xff0c;只需要一行代码就可以实现&#xff1a; "★★★★★☆…

SLAM面试笔记(5) — ROS面试

目录 1 ROS概述 2 ROS通信机制 问题&#xff1a;服务通信概念 问题&#xff1a;服务通信理论模型 3 常见面试题 问题&#xff1a;roslaunch和rosrun区别&#xff1f; 问题&#xff1a;什么是ROS&#xff1f; 问题&#xff1a;ROS中的节点是什么&#xff1f; 问题&…

挠性航天器姿态机动动力学模型及PD鲁棒控制

挠性航天器姿态机动动力学模型及PD鲁棒控制 1挠性航天器姿态机动动力学模型2挠性航天器姿态机动PD鲁棒控制2.1 动力学模型及PD控制律2.2仿真模型2.3 控制程序2.4 被控对象程序2.5 绘图程序2.6 结果 1挠性航天器姿态机动动力学模型 2挠性航天器姿态机动PD鲁棒控制 2.1 动力学模…