作者:@匿名者Unit
目录
- 一.数组指针
- 1.定义
- 2.使用
- 二.数组、指针传参
- 1.一维数组传参
- 2.二维数组传参
- 3.一级指针传参
- 4.二级指针传参
- 三.函数指针
一.数组指针
1.定义
数组指针,顾名思义是指向数组的指针,那数组指针是如何定义的呢
int (*p)[10];
//解释:p先和*结合,说明p是一个指针变量,然后指着指向的是一个大小为10个整型的数组。所以p是一个
//指针,指向一个数组,叫数组指针。
//这里要注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合。
这就定义了一个指向大小为10的整形数组的指针。
2.使用
接下来我们看看数组指针的具体使用:
void print_arr2(int(*p)[5], int row, int col)
{
int i = 0;
for (i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
{
printf("%d ", (*(p+i))[j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = { 1,2,3,4,5,6,7,8,9,10 };
print_arr2(arr, 3, 5);
return 0;
}
如上的传参其实等同
int(*p)[5] = &arr;
所以说arr就等同于p+0,(*(p+i))[j] 等同于 p[i][j]
二.数组、指针传参
1.一维数组传参
void test(int arr[])//ok?
{}
void test(int arr[10])//ok?
{}
void test(int* arr)//ok?
{}
void test2(int* arr[20])//ok?
{}
void test2(int** arr)//ok?
{}
int main()
{
int arr[10] = { 0 };
int* arr2[20] = { 0 };
test(arr);
test2(arr2);
}
arr是一个一维数组通过test传递给函数时,形参可以直接用一维数组接受或者用指针接受,因为数组名代表着数组首元素,指针可以通过首元素地址找到数组所有元素。
2.二维数组传参
void test(int arr[3][5])//ok?
{}
void test(int arr[][])//ok?
{}
void test(int arr[][5])//ok?
{}
void test(int *arr)//ok?
{}
void test(int* arr[5])//ok?
{}
void test(int (*arr)[5])//ok?
{}
void test(int **arr)//ok?
{}
int main()
{
int arr[3][5] = {0};
test(arr);
}
二维数组数组名代表首元素地址,也就是第一行数组的地址,可以用二维数组直接作为形参接受,但是二维数组不可以省略列可以省略行。也可以使用数组指针 接受。
3.一级指针传参
当一个函数的参数部分为一级指针的时候,函数能接收什么参数?
- 变量的地址
- 一级指针
- 一维数组名
4.二级指针传参
当函数的参数为二级指针的时候,可以接收什么参数?
- 二级指针
- 一级指针的地址
- 指针数组名
三.函数指针
函数也有地址,可以对函数进行取地址操作。
函数指针就是存放函数地址的一种指针。
接下来我们看两段代码 来理解函数指针:
//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);
代码1其实是一次函数调用(函数名)(参数);
将0作为一个地址,强制转换为void(*)()的函数指针,再调用。
代码2则更好理解,signal函数有两个参数:int和void(*)(int)的函数指针类型
signal函数返回的是一个函数指针,此函数指针参数为int,返回类型为void
为了便于我们理解,可以写成这样
void (*)(int) signal(int, void(*)(int));
但是这样书写是错误的,当函数返回类型为函数指针的时候不能像普通函数一样,将返回类型写在函数名字前面,而是要将函数体当做函数指针的名字编写。
还有当使用typedef重命名函数指针时,也不能 想普通变量一样将新名字写在类型后面如:
typedef long double lble;
typedef void(*)(int) pfun_t;//错误的
而是要将新名字写在函数指针的名字的位置:
typedef void(*pfun_t)(int);//正确的