在我第二次学习数组与指针的关系时,我还是对指针和数组的关系不甚了解,打算写下这篇博文整理思路,因此适合对指针和数组的关系初有了解的人阅读
数组名的理解
对于数组名,我们做一个简单的回顾:
数组名是数组首元素的地址,但是有两个例外
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("&arr[0] = %p\n", &arr[0]);
printf("arr = %p\n", arr);
return 0;
}
运行上述代码后可看到,两个地址相同:
那两个例外是什么呢???
- sizeof(数组名),数组名单独放在sizeof内部,此时数组名代表整个数组
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%zd\n", sizeof(arr));
return 0;
}
2. &数组名,这⾥的数组名表⽰整个数组,取出的是整个数组的地址(整个数组的地址和数组⾸元素
的地址是有区别的)
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%p\n", arr);
printf("%p\n", arr + 1);
printf("%p\n", &arr + 1);
return 0;
}
(&arr + 1) - (arr)
= 00B5F994 - 00B5F96C = 0x28 = 40 - (十个整形)
(arr + 1) - (arr)
= 00B5F970 - 00B5F96C = 0x4 = 4 - (一个整形)
可见,&数组名代表整个数组的地址
因此,除sizeof(数组名)和&数组名外,数组名是数组首元素的地址
一维数组传参的本质
由上述数组名的理解可以得到,一维数组传的参数是数组首元素的地址,那为什么不传数组过去呢,因为传递的参数是实际参数的临时拷贝,如果数组太大,那消耗的内存就会过多。
因此:⼀维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式。
void test(int arr[])//参数写成数组形式
{
printf("%d\n", sizeof(arr));
}
void test(int* arr)//参数写成指针形式
{
printf("%d\n", sizeof(arr));
}
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
test(arr);
return 0;
}
指针数组和数组指针
指针数组是存放指针的数组
数组指针是指向数组的指针
int main()
{
int arr1[3] = { 1,2,3 };
int arr2[3] = { 4,5,6 };
int arr3[3] = { 7,8,9 };
//指针数组
int* arr[3] = { arr1,arr2,arr3 };
//数组指针
int (*pa)[3] = &arr1;
return 0;
}
!!!注意:[]的优先级要⾼于*号的
在上述代码中
指针数组:int* arr[3]
中arr
先和[3]
结合,表示arr
代表一个数组,这个数组存放的是int*
类型的指针,分别是arr1``arr2``arr3
数组指针:int (*pa)[3]
中pa
先和*
结合,表示pa
是一个指针,再和int [3]
结合,表示这个指针指向了一个存放整形类型的数组
二维数组传参的本质
在写三子棋时,传递的参数是二维数组board[ROW][COL]
:
void InitBoard(char board[ROW][COL], int row, int col);
那我们根据一维数组传参(可以传递一维数组或者指针)的理解,是否也可以传递指针呢?
⾸先我们再次理解⼀下⼆维数组,⼆维数组其实可以看做是每个元素是⼀维数组的数组,也就是⼆维
数组的每个元素是⼀个⼀维数组。那么⼆维数组的⾸元素就是第⼀⾏,是个⼀维数组。
所以,根据数组名是数组⾸元素的地址这个规则,⼆维数组的数组名表⽰的就是第⼀⾏的地址,是⼀
维数组的地址,也就是数组指针。
根据上⾯的例⼦,第⼀⾏的⼀维数组的类型就是型就是数组指针类型int [5]
,所以第⼀⾏的地址的类型
int (*)[5]
。
那就意味着⼆维数组传参本质上也是传递了地址,传递的是第⼀⾏⼀维数组的地址,那么形参也是可以写成指针形式的。
总结:⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式。
函数指针
函数指针和数组指针类似
对于如下代码:
void test()
{
printf("hehe\n");
}
int Add(int x, int y)
{
return x+y;
}
void (*pf1)() = &test;
void (*pf2)() = test;
int (*pf3)(int, int) = Add;
&test
和test
等价
pf1
先和*
结合,表示pf1
是指针,void ()
表示指针指向的内容是一个函数指针,这个函数无参数,也无返回值(void
)
pf3
先和*
结合,表示pf3
是指针,int (int, int)
表示指针指向的内容是一个函数指针,这个函数有两个int
类型的参数,返回值为int
类型