C:数组传参的本质

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)函数外部与函数内部计算数组元素的个数、

来,展示!

可以看到在函数内部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;
}

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;
}

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

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

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

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

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

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

|---|-----|---|-----|-----|-----|-----|-----|---|-----|-----|-----|-----|-----|
| | 1 | | 1 | 2 | 3 | 4 | 5 | | 1 | 2 | 3 | 4 | 5 |
| | int | | int | int | int | int | int | | 2 | 3 | 4 | 5 | 6 |
| | | | | | | | | | 3 | 4 | 5 | 6 | 7 |
| 数组元素 ||| 一维数组 ||| | | | int | int | int | int | int |
| | | | | | | | | | | 二维数组 ||| |

所以我们可以这么理解:

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

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

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

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

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

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

表达形式: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

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

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

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

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

代码就可以改写成这样:

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、总结:

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

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

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


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

相关推荐
student.J13 分钟前
傅里叶变换
python·算法·傅里叶
五味香19 分钟前
C++学习,动态内存
java·c语言·开发语言·jvm·c++·学习·算法
Beauty.56824 分钟前
P1328 [NOIP2014 提高组] 生活大爆炸版石头剪刀布
数据结构·c++·算法
Aurora200526 分钟前
蓝桥杯2024省C
c语言·算法·蓝桥杯
爱棋笑谦26 分钟前
二叉树计算
java·开发语言·数据结构·算法·华为od·面试
蟹至之1 小时前
字符函数 和 字符串函数 的使用与模拟
c语言·字符串·指针·const关键词
小鱼在乎1 小时前
动态规划---最长回文子序列
算法·动态规划
jimmy.hua1 小时前
C++刷怪笼(5)内存管理
开发语言·数据结构·c++
xiaobai12 31 小时前
二叉树的遍历【C++】
开发语言·c++·算法
Freak嵌入式1 小时前
全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类
java·开发语言·数据结构·python·接口·抽象基类