携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第21天,点击查看活动详情
一级指针传参
#include <stdio.h>
void print(int *p, int sz) //一级指针传参,一级指针接收
{
int i = 0;
for(i=0; i<sz; i++)
{
printf("%d\n", *(p+i));
}
}
//void print(int p[],int sz)
//数组接收,也即一级指针接收,不提倡这样写
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9};
int *p = arr;
int sz = sizeof(arr)/sizeof(arr[0]);
//一级指针p,传给函数
print(p, sz);
return 0;
}
思考: 当一个函数的参数部分为一级指针的时候,函数能接收什么参数?
//以int型指针为例
void test(int* p)
{
}
int main()
{
int x=0;
int* px=&x;
int arr[10];
test(&x);//整型地址
test(px);//一级指针
test(arr);//一维数组名,即首元素地址,int*
return 0;
}
二级指针传参
void test(char** p )
{
}
int main()
{
char ch = 'c';
char* pc = &ch;
char* *ppc = &pc;
char* arr[3];
test(&pc); //一级指针的地址,即二级指针
test(ppc); //二级指针
test(arr); //数组名,首元素地址,首元素为一级指针,所以为二级指针
return 0;
}
思考: 当函数的参数为二级指针的时候,可以接收什么参数?
其实和上面一样,你们可以思考一下!
函数指针
首先看一段代码:
#include <stdio.h>
void test()
{
printf("hehe\n");
}
int main()
{
printf("%p\n", test); //函数名 就是函数地址
printf("%p\n", &test); //&函数名 也是函数地址
return 0;
}
运行结果
那么如何将
test()函数指针保存起来呢?
void test()
{
printf("hehe\n");
}
//下面pfun1和pfun2哪个有能力存放test函数的地址?
void (*pfun1)(); //函数指针类型
void *pfun2(); //函数,函数的返回值是void*
函数指针类型 指针都是有类型的 整型指针
int*数组指针int (*)[]函数指针返回值 (*)(参数....)
#include<stdio.h>
int Add(int x, int y)
{
return x + y;
}
int main()
{
int (*pf)(int, int) = Add;
int sum = (*pf)(3, 5); //对函数指针解引用
printf("sum = %d", sum);
sum = pf(3, 5); //因为 Add和&Add相同,即Add等价于 pf
printf("sum = %d", sum);
return 0;
}
有趣的代码
//代码1
(*(void (*)())0)();
//void (*)()为函数指针
//(void (*)())0 将0强制类型抓换成函数指针的地址
//(*(void (*)())0)() *地址,调用0地址处的这个函数
//函数的返回值空,参数为空
//代码2
void (*signal(int , void(*)(int)))(int);
//void(*)(int) 函数指针,返回值void,参数int
//void (*signal(int , void(*)(int)))(int)
// signal是函数名
//返回值是void(*)(int)
// 参数int 和函数指针 void(*)(int)
//这是一个函数的声明
当我们看到代码2很难看懂这个代码! 可以简化吗?
void (*signal(int , void(*)(int)))(int);
//既然这个函数的返回值类型是 void(*)(int)
//那我们可以写成
// void(*)(int) signal(int , void(*)(int));
//但是这样会语法错误 error
函数指针类型重命名
简化
typedef void(*ptr_t) (int); //正确的类型重命名
ptr_t signal(int, ptr_t); //简化
上面的代码出自《C陷阱和缺陷》
有兴趣的伙伴可以尝试阅读!