一、数组
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];
想一想,它们各自表示什么含义呢?
答:
- arr是整型数组
- parr1是整型指针数组,里面存储了10个指针
- parr2是数组指针,一个指向大小为10的数组的指针
- 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小结
- 对于一维数组int arr={1,2,3}来说,数组名arr 表示首元素的地址,除了下面两种情况:
(1)sizeof(arr),此时的arr表示的是整个数组,计算的是整个数组的大小,单位是字节
(2)&arr表示的是整个数组的地址,它和arr是不相同的,&arr是一个整体的数组的首地址,而arr只是数组元素中的第一个元素的地址,他们的数值相同,但加减整数时,所跨越的范围是不同的,这里可以参考上一篇文章,指针类型的解引用加减范围!- 对于二维数组int arr2[3][5]={{1,2,3,4,5},{2,3,4,5,6},{3,4,5,6,7}},来说,数组名arr2表示的是首元素的地址,而二维数组的首元素是一个一维数组,所以二维数组的首元素地址就是其第一行的首地址!
- 对于二维数组而言,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)对一个形参为二级指针的函数,我们传参的时候可以传一个二级指针,也可以传一个一级指针的地址,或者传一个指针数组的数组名(指针数组的数组名就表示数组首元素地址,也就是指针数组里面的指针地址)
请看下面二级指针的图解:
四、感谢与预告
- 本次学习分享到此就结束了,如果本文对你有所帮助,请帮忙点赞+收藏,你的支持就是小编更新的最大动力!🤞
- 预告下一篇文章《关于数组指针和函数指针的辨析》;😘