C:数组传参的本质

server/2024/9/25 4:26:36/

 

1、一维数组传参的本质

数组传参是指在函数调用时将数组作为参数传递给函数。

int main() {int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };test(arr);return 0;}

数组传参只需要写数组名就可以了。注意:数组名是arr,而不是arr[10]

数组传参形参该怎么写呢?

void test(int arr[])//元素个数写不写无所谓

等下会说为什么写不写都不影响

现在我们来分别在(test)函数外部与函数内部计算数组元素的个数、

来,展示!

8b492435519d4d83ba2df923a0a2f2c0.png

可以看到在函数内部sz2结果为1,而函数外部sz1结果为10;这是为什么呢?

关于sz1 = 10;的结果我们都清楚,sizeof(arr)求得数组的总大小,sizeof(arr[0])求得数组首元素的大小,然后得出元素个数,但是为什么在test函数内部求得的元素个数结果变为1了呢?

我们来逆推一下,首先sizeof(arr[0])表示的是数组首元素的大小是不变的,因此sizeof(arr[0])等于4

sz2 = sizeof(arr) / 4 = 1;因此sizeof(arr)也等于4,那么在什么情况下能得到aizeof(arr) = 4 呢?

数组传参的时候 test(arr);我们传递的是整个数组吗?还记得前面关于数组名的理解吗?这里arr既不是在sizeof中,前面也没有&符号,所以,test(arr)中的arr指的就是数组首元素的大小,因此我们传参过去的是首元素的地址,这便是一维数组传参的本质,既如此,我们便可以明白aizeof(arr) = 4是怎么得到的了,地址在32位机器上占4个字节,在64位机器上占8个字节 ,小编是在32位上操作的,所以最终得到izeof(arr) = 4 的结果。

void test(int arr[])//元素个数写不写无所谓
{int sz2 = sizeof(arr) / sizeof(arr[0]);printf("sz2 = %d\n", sz2);
}
#include <stdio.h>
int main() {int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz1 = sizeof(arr) / sizeof(arr[0]);printf("sz1 = %d\n", sz1);test(arr);return 0;}

 综上:数组传参传递的就是首元素地址

1.我们传递的不是整个数组,函数形参的部分是不会真实创建数组的,所以就不需要数组大小,也就是形参部分元素大小写不写都无所谓,没有什么影响

2.数组传过去的是数组首元素地址,地址应该拿指针来接收,所以函数形参部分应该使用指针变量来接收,而我们写成int arr[])是为了更加方便我们的理解。

void test(int arr[])可以写为void test(int* arr)

注意:

一维数组传参的时候,形参可以写成数组的方式,主要是为了方便理解,形参也可以写成指针变量的方式 

如果我们想要在函数内部获取数组元素的个数,该怎么写呢?

void test(int arr[10],int sz)
{//遍历数组int i = 0;for (i = 0; i < sz; i++){printf(" %d ", arr[i]);}
}
#include <stdio.h>
int main() 
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz = sizeof(arr) / sizeof(arr[0]);test(arr,sz);return 0;
}

ef9309fad49f41a09dff5243b6b43356.png

2、二维数组传参的本质

理解二维数组传参的本质

二维数组传参本质上也是传递了地址,传递的是第一行这个一维数组的地址。

我们先来看一个二维数组传参的代码:

#include <stdio.h>
#include <string.h>
void print(int arr[3][5],int a,int b)
{for (int i = 0; i < a; i++) //遍历行数{for (int j = 0; j < b; j++)//遍历列数{printf("%d ", arr[i][j]);}printf("\n");//换行} 
}
int main()
{int arr[3][5] = { 1,2,3,4,5, 2,3,4,5,6, 3,4,5,6,7, };print(arr, 3, 5);return 0;
}

7a5efdb1b3c048c0a63daeeaa29fb76d.png

上列代码中实参是⼆维数组,形参也写成⼆维数组的形式,那我们该怎么理解二维数组传参的操作呢?

071bf622141049d1ae720a4ca11c0c9e.png 从上图中,我们可以看到二维数组传参传递的也是数组名,数组名是什么呢?

数组名是数组首元素的地址,所以二维数组实参传递的是地址,既然传递的是地址,那么形参也就可以使用指针来接收。

这里你可能又会有一个疑问,二维数组数组名到底是表示谁的地址?也就是二维数组的首元素是什么?

这里我们就需要对二维数组做一些更深入的理解了,前面关于数组的介绍篇章也说过

关于二维数组,我们可以把一维数组当作是数组的元素,那么这时候的数组就是二维数组

 

 1 12345 12345
 int intintintintint 23456
         34567
数组元素一维数组   intintintintint
          二维数组 

 所以我们可以这么理解:

二维数组其实是一维数组数组,二维数组的每一个元素都是一维数组

这样我们就可以把二维数组的每一行看作是一个元素,所以二维数组的首元素就是它的第一行

二维数组数组名表示的就是第一行的一维数组的地址。

675ad527cf984cd4a89563b4a00044cb.png

也就是说我们二维数组实参传过去的就是一维数组的地址

形参部分如果想要写成指针的方式,该怎么写呢?

由于实参传递的是数组的地址,所以形参应该使用数组指针来接收

表达形式:int  (*arr)[5],还记得为什么这么写吗?

arr与*结合说明arr是指针,指针指向的是数组 [5]说明数组有5个元素,每个元素类型是int

(*arr)是因为需要arr先于*结合。如果不使用圆括号,arr就不再是指针变量,而是会与[5]结合变为数组名。

C:指针学习-指针变量—学习笔记-CSDN博客

如果对于数组指针有一些不明白的地方,可以看一看这篇文章哟!

参部分用指针改写后:void print ( int(*arr)[5] , int a, int b)

二维数组在内存中是连续存放的,所以

1 2 3 4 5       

2 3 4 5 6                 可以理解为    1 2 3 4 5  2 3 4 5 6  3 4 5 6 7 

3 4 5 6 7                                     

e55fc320961c4061b440078d3f8e7db3.png

到这里是否能够理解二维数组传参的本质了吗?

二维数组传参传递的不是二维数组,而是二维数组首元素的地址,也就是第一行的地址,所以形参的部分要拿数组指针来接收。

 使用指针访问到二维数组的全部元素

图片文字较小,还请见谅,当时画完后没注意到,抱歉抱歉!可以放大观看,如有不理解的地方,也可以私我,我们一起探讨!

cc7fd1b12196462080fe5b60643c1b37.png

代码就可以改写成这样: 

void print(int(*arr)[5], int a, int b)
{for (int i = 0; i < a; i++){for (int j = 0; j < b; j++){printf("%d ", *(*(arr + i)+j));}printf("\n");} 
}

是不是感觉这样写不是很好理解,还可以换一种方式写*(*(arr + i)+j)

*(*(arr + i)+j)也可以写成arr[i][j]

这两种一种是指针的方式,一种使用数组下标的方式。

3、总结:

数组传参传递的都是地址,所以形参都可以使用指针来接收

一位数组传参传递的是首元素地址,使用(类型)指针来接收,

二维数组传参传递的是一维数组的地址,使用数组指针来接收。


本篇文章到这里就结束了,希望能够对大家理解数组传参有所帮助!

 


http://www.ppmy.cn/server/101584.html

相关文章

网络效能精进:从根源剖析到策略实施

网络效能精进&#xff1a;从根源剖析到策略实施 在当今数字化时代&#xff0c;网络性能直接关系到企业运营的流畅度与用户体验的质量。本文旨在深入探讨网络性能优化的全过程&#xff0c;从问题诊断的细致入微到解决方案的精准实施&#xff0c;为企业网络效能的提升提供一套系…

【ubuntu24.04】docker安装

安装docker sudo apt install apt-transport-https curlsudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin安装的组件包括:docker-ce:Docker Engine。 docker-ce-cli:用于与 Docker 守护进程通信的命令行工具。 containe…

24/8/17算法笔记 模仿学习算法

模仿学习&#xff08;Imitation Learning&#xff0c;IL&#xff09;算法是强化学习领域的一个分支&#xff0c;它关注于让智能体通过模仿专家的行为来学习任务。模仿学习通常用于学习复杂任务&#xff0c;尤其是当通过传统的强化学习算法直接学习效率较低或成本较高时。以下是…

vim中跳转头文件

在 Vim 中&#xff0c;你可以通过以下几种方式跳转到系统头文件的定义&#xff1a; 1. 使用 gf 命令 在 Vim 中&#xff0c;将光标移动到头文件的名称上&#xff08;例如 #include <iostream>&#xff09;。按 gf&#xff08;goto file&#xff09;&#xff0c;Vim 会尝…

B站搜索建库架构优化实践

前言 搜索是B站的重要基础功能&#xff0c;需要对包括视频、评论、图文等海量的站内优质资源建立索引&#xff0c;处理来自用户每日数亿的检索请求。离线索引数据的正确、高效产出是搜索业务的基础。我们在这里分享搜索离线架构整体的改造实践&#xff1a;从周期长&#xff0c;…

MySQL 异步主从复制流程解析

前言&#xff1a; 首先MySQL主从复制方式有多种&#xff0c;包括 binlog、GTID等&#xff0c;这里基于 binlog 的形式&#xff0c;解析异步主从复制流程 首先通过下面命令查看全部 binlog 日志文件 show binary logs; binlog 日志文件如下&#xff1a; 然后查看其中一个文件…

MySQL:表的设计原则和聚合函数

所属专栏&#xff1a;MySQL学习 &#x1f48e;1. 表的设计原则 1. 从需求中找到类&#xff0c;类对应到数据库中的实体&#xff0c;实体在数据库中表现为一张一张的表&#xff0c;类中的属性对应着表中的字段 2. 确定类与类的对应关系 3. 使用SQL去创建具体的表 范式&#xff1…

pytorch实现单层线性回归模型

文章目录 简述代码重构要点 数学模型、运行结果数据构建与分批模型封装运行测试 简述 python使用 数值微分法 求梯度&#xff0c;实现单层线性回归-CSDN博客 python使用 计算图&#xff08;forward与backward&#xff09; 求梯度&#xff0c;实现单层线性回归-CSDN博客 数值微分…