一级指针二级指针的传参
一级指针传参
若自定义函数的形参为一级指针变量,在调用此函数时要如何传递参数?
- 接收是指针变量,则传递也可以是指针变量。
- 接收的是指针变量,则传递可以是地址。
void test1(int* p)
{
}
//若接收为指针变量,可以传递什么样的参数
void test2(char* str)
{
}
int main()
{
int arr[5] = {
1, 2, 3, 4, 5 };
int* p = arr;
test1(p); //使用指针变量传参
test1(arr); //使用数组名传参
char b = 'w';
test2(&b); //对变量进行取地址后传参
char* p1 = &b;
test2(p1);
return 0;
}
多数情况下数组名表示首元素地址(如上图,右面是整型数组,左面是数组中每个元素的地址),因此可以直接作为参数进行传递;可以对变量进行取地址之后(&变量名
)进行传递;还可以直接传递指针变量。
数组名代表首元素地址的两种情况:
sizeof(数组名)
——此时,数组名表示整个数组。&数组名
——表示取整个数组的地址。
二级指针传参
自定义函数的形参是二级指针调用时如何传递参数呢?
- 可以通过二级指针,进行传参。
- 使用一级指针的地址进行传参。
- 指针数组的数组名可以直接用来传参。
void test(int** p)
{
}
int main()
{
int a = 10;
int* pa = &a;
int** ppa = &pa; //不能这样写&(&a)
//可以传二级指针
test(ppa);
//可以传一级指针的地址
test(&pa);
int* b[5] = {
0 };
//数组名表示首元素地址,因此可以传递指针数组名
test(b);
return 0;
}
如上面代码展示的,二级指针不能写为:int** ppa = &(&a);
为什么呢?请看下图:
上图是对变量a
的地址及其存储内容。
上图是一级指针变量pa
的地址及其存储内容。
上图是二级指针变量ppa
的地址及其存储内容。三者的关系如下图:
一级指针pa
中存放的是变量a
的地址,二级指针内部存放的是一级指针的地址,并不是一级指针内部存放的内容。而&a
拿到了a
的地址,但并没有为它开辟内存空间,因此无法进行二级指针操作。
指针数组中的元素是指针,数组名还表示首元素地址,因此指针数组的数组名可以进行传参。举个栗子:
void test(int** p)
{
}
int main()
{
int b = 4;
int c = 3;
int d = 2;
int* e[3] = {
&b, &c, &d };
test(e);
return 0;
}
变量b、c、d
的地址分别为:
数组e
中存放变量b、c、d
的地址,数组名表示首元素地址0x004FF7DC
类似于一级指针其可以作为参数进行传递。
函数指针
函数指针
函数名就是地址。函数指针——指向函数的指针。函数指针的创建:指向函数的返回类型 (*函数指针变量)(指向函数的形参类型) = &指向函数(不用&也可以);
,以一个简单的例子对函数指针的创建进行简要描述:
int Add(int x, int y)
{
return x + y;
}
int main()
{
//函数指针的创建,首先其为指针要表示为*pf,(*pf)()表示其指向函数,
//(int, int)是其指向函数的形参类型,int表示返回类型
int (*pf)(int, int) = &Add;
//传参,首先将函数指针解引用,再传参数,这颗*没有意义,只是为了方便理解
int ret = (*pf)(3, 5);
//也可以这样, Add==pf
int num = pf(3, 5);
printf("%d\n", num);
printf("%d\n", ret);
//还需要注意,函数指针的&Add和Add的具有同样的意义。
printf("%p\n",&Add);
printf("%p\n",Add);
return 0;
}
代码中Add
和等价于pf
,可以直接通过pf
进行传参。代码的输出结果为:
&Add
和Add
输出的地址一致,两者意义相同,注意区分数组的地址&arr
和数组名arr
,两者输出的地址也一样,&arr
表示整个数组的地址,arr
表示数组首元素的地址。
int main() { int arr[5] = { 1, 2, 3, 4, 5}; printf("%p\n", &arr); printf("%p\n", arr); printf("%p\n", &arr+1); printf("%p\n", arr+1); return 0; }
&arr
是整个数组的地址,但其和arr
都指向首元素地址,不同在于将其加1之后跳过的是整个数组(此例中数组大小为 5 × 4 = 20 5\times4=20 5×4=20个字节),地址从0x00D3F8E0
到0x00D3F8F0
,注意&arr+n
跳过的是n
个数组大小,此时以数组为单位,而arr+1
表示从首元素地址跳至第二个元素地址。
尝试理解下面两行代码以加深对函数指针的理解(这里内容很多而且难理解,一定要好好看完):
(*(void (*)())0)();
// 第一步:void (*)()表示函数指针。