目录
写在前面
上篇文章介绍了指针数组和数组指针,有兴趣的小伙伴可以看一看。
在写程序时,有时难免要把数组或指针传给函数,我们又该怎么写参数呢?开门见山,有两种方法:
- 照着原函数写
- 用指针接收
一、数组传参
一维数组传参
法一:test1和test2的前两项是照着原函数写,
法二:test1和test2的第三项是用指针接收
#include<stdio.h>
void test1(int arr[])//正确
{}
void test1(int arr[10])//正确
{}
void test1(int* arr)//正确
{}
void test2(int* arr[])//正确
{}
void test2(int* arr[10])//正确
{}
void test2(int **arr)//正确,用来存放一级指针变量的地址
{}
int main()
{
int arr1[10]={0};
int* arr2[10]={0};
test1(arr1);
test2(arr2);
return 0;
}
上面的6种写法 来接收函数传来的地址 均是正确的。
难点解释:
第一种理解方式:test2 中 arr2是首元素地址,也就是一个整形指针的地址,我们当然可以用一个二级指针来接受一级指针的地址,
另一种理解方式:int** arr2 ,写参数时可以理解成 (int*) (*arr2),前一部分可以理解成原函数的类型,后一部分可以理解成一个新命名的指针。
知识补充:
test1函数中,传来的是数组的首元素地址,所以我们可以定义int arr[ ],int arr[一个数字],数组大小可以不写,因为在32位平台,数组首元素大小,也就是指针大小固定4个字节,写不写都没有意义,但写的话就不要写错,以免引起误导。
二维数组传参
法一:第一个test是照着原函数写
法二:后面4个是用指针接收
#include<stdio.h>
void test(int arr[3][5])//正确
{}
void test(int *arr)//错误,整形指针不能接收数组的地址
{}
void test(int* arr[5])//错误,指针数组
{}
void test(int (*arr)[5])//正确,数组指针 可以存放数组的地址
{}
void test(int **arr)//错误,用来存放一级指针变量的地址
{}
int main()
{
int arr[3][5]={0};
test(arr);
return 0;
}
知识补充:
二维数组的参数中,第一个行参数可以不写,但第二个列参数必须写!
二、指针参数
一级指针传参
#include<stdio.h>
void test(int* p)//正确
{}
int main()
{
int a=0;
int* p=&a;
test(&a);//正确
test(p);// 正确
return 0;
}
把int 类型改为 char 类型亦是如此
二级指针传参
有问有答:形参是二级指针,能传什么实参呢?
- 一级指针变量的地址
- 二级指针变量本身
- 存放一级指针的数组名,也就是指针数组名
#include<stdio.h>
void test(int **p)
{}
int main()
{
int a=0;
int* p=&a;
int** pp=&p;
test(&p);
test(pp); //两个test等价
return 0;
}
三、函数传参
基本格式:函数返回类型+指针变量+函数类型
#include<stdio.h>
int add(int x,int y)
{
int z=0;
z=x+y;
return z;
}
int main()
{
int a=3;
int b=5;
printf("%d",add(a,b));
return 0;
}
//上面的函数是普通的传参,下面是与其对照的函数传参
#include<stdio.h>
int add(int x,int y)
{
int z=0;
z=x+y;
return z;
}
int main()
{
int a=3;
int b=5;
int (*p)(int,int)=add;
printf("%d",(*p)(3,5));
return 0;
}
难点解析:
- int* p(int,int)=add; 如果我们这样写,就是这样理解的:p是函数名,(int ,int)表示add函数的两个整形参数,int* 就是返回类型,这显然与我们的预期,用指针存放add函数的地址,有出入。
- int (*p)(int,int)=add;用来接收函数地址,其基本格式为函数返回类型+指针变量+函数类型=函数名
- (*p)就可以表明p是指针变量。
- (int,int)表示add函数的两个整形参数。
- int 表示add函数的返回类型。
- (*p)(3,5) 是对函数的调用: p存放函数地址,*p就是add函数,等价于add(3,5)
add(3,5) ⇔ (*p)(3,5) ⇔ p(3,5) ⇔ (**p)(3,5) 实际上*再多就没有意义了
我们进行一个简单应用:打印结果为hello world
#include<stdio.h>
void print(char* str)
{
printf("%s",str);
}
int main()
{
void (*p)(char*)=print;
(*p)("hello world");
return 0;
}
四、看懂代码
细细理解下面的代码你会对指针有更加深刻的理解,不了解函数指针基本格式的,可以再看看上面。
一、(*(void(*)())0)()——调用0地址处的该函数(无参无返回类型)
拆分:(* ( void(*)() )0 ) ()
- void(*)() 是函数指针类型
- ()0 是强制类型转换,例如(int)5.0,就是5,在这里就是将0强制类型转换为函数地址
- *( void(*)() )0 0既然是地址,那么*解引用之后,就找到了函数
- 最后面的()是对函数的调用,并且没有传参
翻译解释:把0强制类型转换为一个函数指针类型,该指针指向哪个函数是无参返回类型是void,当0变成一个函数地址之后,对它进行解引用操作,去调用以0为地址处的该函数。
二、void(* signal(int, void(*)(int) ) )(int)
拆分:void(* signal(int, void(*)(int) ) )(int)
signal(参数一, 参数二),随后再把这一部分套进函数参数中就完成复原。
翻译解释:void(* signal(int, void(*)(int) ) )(int) 大概意思就是自定义函数signal里面定义两个参数,一个为int类型,一个为函数指针类型(该函数指针指向的函数的参数为int,返回类型是void), signal函数的返回类型也是一个函数指针,该函数指向的函数参数为int,返回类型为void
写在最后
创作不易,还希望各位大佬支持!
👍🏻点赞,你的认可是我创作的动力!
⭐收藏,你的青睐是我努力的方向!
✏️评论,你的意见是我进步的财富!