数组指针
概念:数组指针是指针,只要是指针他就占4个字节;
例如: 整形指针:int *p;能够指向整形数据的指针
浮点型指针:float *p;能够指向浮点型的数据的指针
那么数组指针,同样的理解就是指向数组的指针。
Eg: int (*p)[10]
解释:这里的p由于小括号的原因和*先结合,所以他就是指针,然后指向的是一个大小为10的整形数组,所以p首先是一个指针,然后指向一个整形数组,即p的名字叫做数组指针。
使用:
Int arr[10] = {0};
此时:arr表示:数组首元素的地址
&arr 表示:数组的地址
我们运行下面一段代码,得到结果如图:
arr代表数组的第一个元素,所以打印出数组第一个元素的地址
arr+1代表数组第一个元素向后加一个,得到了的第二个元素,因为是整形数组,所以,地址加了一个4
&arr+1:因为&arr代表的是整个数组的地址,所以在+1之后,代表的是下一个数组的地址。
指针数组
根据数组指针是指针的理解,我们可以得到,指针数组就是数组,其数组的元素都是指针。
Eg:一个以为指针数组的定义:int *p[10];
因为[]的结合优先级比较高,所以p先和[]结合
指针数组常用来指向字符串,方便字符串的处理
数组参数 和 指针参数
一维数组的传参:
没有报错,说明图中的传参方式都可以作为一维数组的传参方式
二维数组的传参:
当运行这段代码的时候,会出现第一个函数的报错,提示缺少下标,当我们在一个函数的参数的第二个中加上二维数组的列数:5,则编译通过,说明二维数组在传参的过程中是必须要传列数的。
一级指针传参
当一个函数的参数部分是一级指针的 时候,那么此时我们可以给参数传进去一个地址,因为指针里面就是地址,也可以传进去一个指针,此时编译都可以通过,所以,我们在一定的程度上就可以把:地址=指针
二级指针传参
在运行如图代码之后,test函数的参数就是接收一个二级指针,在调用的时候,第一次直接传进去一个二级指针:调用成功。因为二级指针里面存放的是一个一级指针的地址,所以我们在第二次调用的时候,传进去一个一级指针的地址&p,显示调用成功,所以:函数的参数是二级指针的时候,可以接收一个二级指针或者一级指针的地址作为参数。
函数指针
首先运行一段代码:
可以看到test 和&test的值是一样的,所以此时,我们就可以把test看作是函数的地址,
阅读一下代码帮助理解:
Void test(){
Printf(“hehe\n”);
}
//void (*p1)()
//void *p2()
此时只有p1可以存放函数test的地址,p1先和*结合,说明p1是指针,指针的指向是一个函数,指向的这个函数没有参数,返回值的类型是void。
函数指针数组:
首先它是一个数组,存放的元素是指针,这些指针都指向某个函数。
则其定义为:
例如:int (*parr1[10])()
首先parr1先和[]结合,他就是数组,那么数组的内容就是int (*)()类型的函数指针
错误实例: int *parr1[10]()×
int (*)()parr3[10] ×
函数指针数组的用途:转移表
在我们设计一个计算器的时候:
我们用函数指针数组,将加减乘除四个函数存放起来,
调用时,我们可以:*pcal[1](3,2),此时我们将调用add函数进行3和2 加运算
函数指针数组的指针
既然数组可以用指针指,叫做数组指针,那么函数指针数组也可用指针指起来,叫做:函数指针数组的指针,顾名思义,这个指针指向了一个数组,这个数组叫做函数指针数组,数组里面的元素存放的是函数的指针,这些函数的指针,分别的指向了特定的函数。
如何定义:
Void test (const char *str){}
Int main(){
//定义函数指针pfun
Void (*pfun)(const char *) = test;
//函数指针的数组pfunarr
Void (*pfunarr[5])(const char *str);
//函数指针数组的指针
//void (*(*pfunarr[5]) )(const char *) = &pfunarr;
Return 0;
}
函数指针的应用:回调函数
例如:
Int test(void *str1,void *str2){}
void fun(int x,const char* str,int(*funname)(void *,void*)){
//函数体内部会调用第三个参数传进来的函数,返回值是int,有两个参数,都是void型
}
Int main(){
Fun(a,str,test);//此时test函数就当做参数传递到fun函数里面
Return 0
}