【C语言进阶】⑤关于数组传参和指针传参辨析

一、数组
1.1.一维数组
  • int arr1[]={1,2,3,4,5,6,7,8};
  • 数组名 arr1 一般表示的是首元素的地址,以下两种情况除外:
    (1)&arr1表示整个数组元素的地址;
    (2)sizeof(arr),其中arr表示的是整个数组,sizeof(arr)计算的是整个数组的大小,单位是字节;
  • arr和&arr的辨析,请下面图解:
    在这里插入图片描述
1.2.二维数组
  • int arr2[3][5] = {{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7,}};
  • 而此时arr2也表示数组首元素的地址,但对于二维数组而言,它的首元素地址就是他第一行的地址;
  • 请看下面图解
    在这里插入图片描述
1.3.指针和数组

请看下面事例:

●int arr[5];
●int *parr1[10];
●int (*parr2)[10];
●int (*parr3[10])[5];

想一想,它们各自表示什么含义呢?

答:

  1. arr是整型数组
  2. parr1是整型指针数组,里面存储了10个指针
  3. parr2是数组指针,一个指向大小为10的数组的指针
  4. parr3是一个存储int(*)[5],即存储数组指针的数组。

例如:我们知道int arr[3];表示一个int类型含有3个元素的数组,而对于parr3[10]则也表示一个数组,去掉parr3[10]后,这个int(*)[5],我们知道是表示一个指向含有五个元素的数组的指针;所以int(*parr3[10])[5],则表示parr3是一个储存数组指针的数组,该数组能储存10个数组指针,而每个数组指针又指向一个含有5个元素的数组,每个元素是int类型。
请看图解
在这里插入图片描述

二、数组传参
2.1一维数组传参

请看事例1:

①void test(int arr[]){} 
②void test(int arr[10]){}
③void test(int *arr){}
④void test2(int *arr[20]){}
⑤void test2(int **arr){}
int main()
{
  int arr[10] = {0};
  int *arr2[20] = {0};
  test(arr);
  test(arr2);
 }

分析1: 对于test(arr):
(1)①void test(int arr[]){} :
arr是一个int类型数组,数组名arr表示数组首元素地址,此时实参传到①时,可行;因为,我们知道此时传递过去的是数组arr的首地址,而①中的形参也是一个数组,虽说这个形参数组没有设置大小,但是我们知道,本质上来说,形参只是接收传过来的地址,并不会真的会在内存中开辟一个内存空间去存放传过来的实参;所以,传一个数组首元素地址,我们拿一个数组来接收,没问题!
(2 ②void test(int arr[10]){}:
实参arr传递到②,可行,但是实际上此时的形参int arr[10],并不会在内存中开辟一个大小为10的内存空间,此时的10是没有意义的,可写可不写。
(3)③void test(int *arr){}:
实参arr传递到③时,可行;我们知道此时的实参arr表示一个整型的地址,而对于③void test(int *arr)来说,拿一个int类型的指针作为形参来接收实参arr(整型地址),指针变量就是储存地址的,而此时int类型地址用int类型指针来储存,完全没有问题!

分析2.:对于 test(arr2)
(1) int *arr2[20] = {0};
arr2是一个指针数组,存储了20个指针;此时数组名arr2表示的是第一行首元素的地址,而我们知道,arr2储存的都是int类型的指针(int*),所有总的来说,arr2表示的是首元素int类型的指针的地址;
(2)④void test2(int *arr[20]){}:
此时arr2作为实参传递到④,而void test2(int *arr[20]),用一个指针数组来接收,没问题,而且我们知道形参里面20是没有意义的,可以不写。
(3)⑤void test2(int **arr){}:
当arr2作为实参传递到⑤时,对于void test2(int **arr),我们知道此时int *arr表示一个二级指针,一个指向int类型指针(int)地址的二级指针,而实参传过去的也是一个int类型的指针的地址,用二级指针来接收,完全没问题,而且只能用二级指针来接收,其他的都不行!

2.2二维数组传参

请看事例2

①void test(int arr[3][5]){}
②void test(int arr[][]){}
③void test (int arr[][5]){}
④void test(int *arr){}
⑤void test (int* arr[5]){}
⑥void test(int (*arr)[5]){}
⑦void test(int **arr){}
int main()
{
  int arr3[3][5] = {0};
  test(arr);
}

分析: test(arr);
(1)①void test(int arr[3][5]){}:
实参arr3传到①,可行;二维数组传给二维数组,完全没问题;
(2)②void test(int arr[][]){}:
实参arr3传到②,不可行;因为我们知道,对于二维数组int arr[3][5]而言,只能省略第一个[],所有程序运行时,编译器会报错!
(3)③void test (int arr[][5]){}:
实参传到③,可行;
(4)④void test(int *arr){}:
不可行;我们知道二维数组传参时,arr3表示的是首元素的地址,二维数组的首元素地址是第一行(一维数组)的地址;所以实参为arr3二维数组的首元素一维数组地址,但是用形参一级指针int* arr来接收一个含有五个元素的数组的地址是不可行的;必须用一个含有五个元素的数组指针来接收
(5)⑤void test (int* arr[5]){}:
此时void test(int* arr[5]),形参部分表示的是一个指针数组(存储的是int类型指针),用一个指针数组(是数组,不能接收地址),来接收一个二维数组的地址是不可行的;
(6)⑥void test(int (*arr)[5]){}:
此时void test(int (*arr)[5])是一个数组指针,表示的是一个指向含有五个元素的数组的指针,用它来接收二维数组首元素的地址,因为我们知道,这个二维数组的首元素也是一个含有五个元素一维数组,所有完全没有问题!
(7)⑦void test(int **arr){}:
void test(int **arr)表示的是一个二级指针;用二级指针来接收二维数组的首元素地址是不可行的,因为实参二维数组传过去的不是一个二级指针,而是一个含有五个数组指针;
}

2.3小结
  1. 对于一维数组int arr={1,2,3}来说,数组名arr 表示首元素的地址除了下面两种情况:
    (1)sizeof(arr),此时的arr表示的是整个数组,计算的是整个数组的大小,单位是字节
    (2)&arr表示的是整个数组的地址,它和arr是不相同的,&arr是一个整体的数组的首地址,而arr只是数组元素中的第一个元素的地址,他们的数值相同,但加减整数时,所跨越的范围是不同的,这里可以参考上一篇文章,指针类型的解引用加减范围!
  2. 对于二维数组int arr2[3][5]={{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}},来说,数组名arr2表示的是首元素的地址,而二维数组的首元素是一个一维数组,所以二维数组的首元素地址就是其第一行的首地址
  3. 对于二维数组而言,int arr3[][5]={0};
    第一个[]里面的数值可以省略不写,但第二个[]里的数值必须写!
三、指针传参
3.1一维指针传参

请看下面事例

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

分析:

当我们要使用某个函数时,我们先要看这个函数的参数是什么,如果是一个一级指针,那么我们就可以传一个相同类型的一级指针,或者传一个类型相同的地址过来;
如:对于void test(char* p){…}这个函数而言,我们就可以给它传递一个指针
char ch= 'c'; char* p =&ch;test(p);也可以直接传递test(&ch);

3.3二级指针传参

请看下面事例

void test(int** p2)
{
**p2=2;//修改指针指向地址内的值
}
int main(){
int a=10;
int* pa = &a; 
int** ppa = &pa;//此时paa是一个二级指针,指向一级指针的指针,里面包含了一级指针的地址;
test(ppa);
test(&pa);
printf("第一次传二级指针和一级指针的地址时a的值:%d\n",a);
int* arr[10]={0};
test(arr);//传存放一级指针的数组
printf("第二次传一级指针的数组的地址时a的值:%d\n",a);
return 0
}

分析:

事例中:
(1)pa是一个一级指针,存放的是变量a的地址;
(2)paa是一个二级指针,指向一级指针的指针,里面存放了一级指针的地址;
(3)对一个形参为二级指针的函数,我们传参的时候可以传一个二级指针,也可以传一个一级指针的地址,或者传一个指针数组的数组名(指针数组的数组名就表示数组首元素地址,也就是指针数组里面的指针地址)
请看下面二级指针的图解:
在这里插入图片描述

四、感谢与预告
  1. 本次学习分享到此就结束了,如果本文对你有所帮助,请帮忙点赞+收藏,你的支持就是小编更新的最大动力!🤞
  2. 预告下一篇文章《关于数组指针和函数指针的辨析》;😘
评论 27
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

白杨Cc

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值