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]结合变为数组名。
如果对于数组指针有一些不明白的地方,可以看一看这篇文章哟!
参部分用指针改写后: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、总结:
数组传参传递的都是地址,所以形参都可以使用指针来接收
一位数组传参传递的是首元素地址,使用(类型)指针来接收,
二维数组传参传递的是一维数组的地址,使用数组指针来接收。
本篇文章到这里就结束了,希望能够对大家理解数组传参有所帮助!