您的位置:首页 > 其它

高级指针

2016-05-01 14:43 232 查看
(一)、二维数组与二级指针参数

二维数组做参数:
二维数组做参数与一维数组做参数一样,传递的都是首元素的地址,只不过二维数组的每个元素又是一个一维数组 。
例:int arr[5][10];
这是一个5行10列的整形数组,可以将它看成一个只有5个元素的一维数组,只不过每个元素又是一个大小为10的一维数组。

fun(arr);我们来分析一下当arr作为实参是,需要什么类型的形参来接受它???
arr作为参数时,代表首元素地址,要接受这个地址必须是一个指针或者是一个数组,但是他的每个元素的类型是int[10]。

所以我们可以用一个指向类型为int [10]的数组指针来接受arr[5][10],即:int (*p)[10] 。 同样也可以用一个数组来接受arr,即:int arr1[][10],这里第二维的大小不能省略,在这里int arr1[][10] 也可以被解析成int (*arr1)[10];

二级指针做参数:
例:char *p[5];
这是一个大小为5,每个元素都是char *类型的数组,当他作为实参时,需要什么样类型的形参来接受他呢???

fun(p); 分析:既然p是一个数组,那么数组在作为实参时,实际上传递过去的是首元素的地址,但是p的每一个元素都是一个char *类型,也是一个地址,所以形参的类型应该是char **。

总结:





数组名只有在sizeof()和取&时才不发生降级,其余地方都代表首元素地址。

(二)、函数指针

函数指针: 是一个指向函数的指针
声明:
例:void (*p)(); 首先p是一个指针,它指向一个返回值为空,参数为空的函数。
初始化:
要明确,函数指针本质还是一个指针,既然是指针,那么就必须给他进行初始化才能使用它,下面来看一看函数指针的初始化,定义一个返回值为空参数为空的函数:void fun()。
p=fun;
p=&fun;
这两种初始化的方式都是正确的。因为函数名在被编译后其实就是一个地址,所以这两种方式本质上没有什么区别。
调用:
p();
(*p)();
这两种方式都是正确的。p里面存的fun的地址,而fun与&fun又是一样的。

例:分析一下(*(void (*) () ) 0 ) ()是个什么东东!!!
首先,void (*) ();是一个返回值为空,参数为空的函数指针类型。
void (*) () 0 ; 它的作用是把0强制类型转换成一个返回值为空,参数为空的函数指针。
(*(void (*) () )0) ; 找到保存在0地址处的函数。
(*(void (*) () ) 0 ) (); 对这个函数进行调用。

用途:
1、回调函数:用户将一个函数指针作为参数传递给其他函数,后者再“回调”用户的函数,这种方式称为“回调函数”,如果想要你编写的函数在不同的时候执行不同的工作,这时就可以使用回调函数。回调函数也算是c语言里面为数不多的一个高大上的东西。
2、转换表:转换表本质上是一个函数指针数组,说白了就是一个数组,只不过数组里面存放的全部都是函数指针。
例:实现一个计算器
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
int Add(int a, int b)
{
return a + b;
}
int Sub(int a, int b)
{
return a - b;
}
int Mul(int a, int b)
{
return a *b;
}
int Div(int a, int b)
{
assert(b != 0);
return a / b;
}
int operator(int (*fun)(int,int))   //回调函数
{
int a = 0;
int b = 0;
printf( "请输入操作数:" );
scanf( "%d%d", &a, &b);
return (*fun )(a,b);
}
int main()
{
printf( "*************************************\n" );
printf( "*0.exit           1.Add****\n" );
printf( "*2.Sub           3.Mul****\n" );
printf( "*4.Div           *********\n" );
int(*fun[5])(int ,int);         //转换表
fun[1] = Add;
fun[2] = Sub;
fun[3] = Mul;
fun[4] = Div;
int input = 1;
while (input)
{
printf( "请选择> " );
scanf( "%d", &input);
if (input<0 || input>4)
{                                                               printf( "选择无效\n" );
}
else if (input == 0)
{                                                    break;
}
else
{                                                           int ret = operator(fun[input]);
printf( "%d\n", ret);
}
}
system( "pause");
return 0;
}


在这个计算器程序中,就使用到了转换表fun[]。fun[]里面存放了加减乘除四个函数,根据input的不同,fun[input]调用不同的函数。这种方式与switch() case的功能比较相似,不过转换表比switch()case更简单。

函数指针数组:
函数指针数组是一个指针数组,也就是一个数组,只不过里面存放的全都是函数指针。
声明:例: char* (*p[5])(int,int);
p与[5]先结合成一个数组,所以这是一个大小为5的数组,数组元素的类型是一个函数指针,这个函数指针指向一个返回值为char *,有两个参数,且参数类型为int,int的数组。
可以这样理解:char * (*)(int,int) p[5]; 其中char*(*)(int int)是p[5]的类型。

函数指针数组的指针:
函数指针数组的指针是一个数组指针,本质上是一个指针,只不过指向的是一个存放函数指针的数组。
声明:例:char *(*(*p)[5])(int,int);
*与p先结合成一个指针,所以p是一个指针,指针所指向的是一个大小为5的数组,这个数组存放的是函数指针,这些函数指针所指向的类型是返回值为char *,有两个int型参数的函数。
可以这样理解: char *(*[5])(int,int) *p; p是一个指针,类型是char*(*[5])(int,int).

总结:指针数组,是一个数组,里面存放的是指针。
数组指针,是一个指针,指向一个数组的指针。
函数指针数组,是一个数组,里面存放的是函数指针。
函数指针数组指针,是一个指针,指向一个存放函数指针的数组。
其实规律很简单,强调的都是最后两个字,最后两个字是什么他就是什么,而前面的字就是他的类型。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  指针 高级