标签:高级指针
(一)、二维数组与二级指针参数
二维数组做参数:
二维数组做参数与一维数组做参数一样,传递的都是首元素的地址,只不过二维数组的每个元素又是一个一维数组 。
例: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).
总结:指针数组,是一个数组,里面存放的是指针。
数组指针,是一个指针,指向一个数组的指针。
函数指针数组,是一个数组,里面存放的是函数指针。
函数指针数组指针,是一个指针,指向一个存放函数指针的数组。
其实规律很简单,强调的都是最后两个字,最后两个字是什么他就是什么,而前面的字就是他的类型。
本文出自 “11132019” 博客,请务必保留此出处http://11142019.blog.51cto.com/11132019/1769320
标签:高级指针
原文地址:http://11142019.blog.51cto.com/11132019/1769320