左右声明法则:
首先从最里面的圆括号(未定义的标识符)看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明
修正:
笔者要对这个法则进行一个小小的修正,应该是从未定义的标识符开始阅读,而不是从括号读起,之所以是未定义的标识符,是因为一个声明里面可能有多个标识符,但未定义的标识符只会有一个。
链接:https://www.cnblogs.com/Lunais/p/5969181.html
int (*func)(int *p);
首先找到那个未定义的标识符,就是func,它的外面有一对圆括号,而且左边是一个*号,这说明func是一个指针,然后跳出这个圆括号,先看
右边,也是一个圆括号,这说明(*func)是一个函数,而func是一个指向这类函数的指针,就是一个函数指针,这类函数具有int*类型的形参,返回值类型是 int。
#include <stdio.h>
int max( int *p )
{
return 0;
}int main ()
{
int *k;
int (*func)(int *p) = &max;
func( k );return 0;
}
int (*func)(int *p, int (*f)(int*));
func被一对括号包含,且左边有一个*号,说明func是一个指针,跳出括号,右边也有个括号,那么func是一个指向函数的指针,这类函数具有int *和int (*)(int*)这样的形参,返回值为
int类型。再来看一看func的形参int (*f)(int*),类似前面的解释,f也是一个函数指针,指向的函数具有int*类型的形参,返回值为int。
#include <stdio.h>
int max( int *p )
{
return 0;
}int test( int *pt, int (*f)(int*))
{
return 0;
}int main ()
{
int *k;
int (*func)(int *p, int (*f)(int*)) = &test;
func( k, &max);return 0;
}
int (*(*func)(int *p))[5];
func是一个函数指针,这类函数具有int*类型的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。
#include <stdio.h>
typedef int(*TYPE)[5];
TYPE fun( int *k )
{
int a[5];
TYPE p=&a;
return p;
}int main ()
{
//func是一个函数指针,这类函数具有int*类型的形参,返回值是指向数组的指针
//所指向的数组的元素是具有5个int元素的数组。
int (*(*func)(int *p))[5] ;
func = &fun;
return 0;
}
int (*func[5])(int *p);
func右边是一个[]运算符,说明func是一个具有5个元素的数组,func的左边有一个*,说明func的元素是指针,要注意这里的*不是修饰 func的,而是修饰func[5]的,原因是[]运算符优先级
比*高,func先跟[]结合,因此*修饰的是func[5]。跳出这个括号,看右边,也是一对圆括号,说明func数组的元素是函数类型的指针,它所指向的函数具有int*类型的形参,返回值类型为
#include <stdio.h>
int max( int *p )
{
return 0;
}int main ()
{
int (*func[5])(int *p);
func[0] = &max;return 0;
}
double (* (* P1)[10] )( double k );//数组指针,第一个*说明数组中包含的是指针,往右是参数列表,说明数组中包含的是函数指针,这些函数没有参数,返回值类型是double
#include <stdio.h>
/* "*(*P2[10])()"用typedef分解及使用 */
typedef double ( * ppt )( double k );
typedef ppt (*p)[2];double M( double k )
{
return k;
}double L( double k )
{
return k + 1;
}int main ()
{
double (*mm)(double k);
p a;
ppt arry[2] = { &M, &L };
a = &arry ;
mm = **a;//得到&M地址
mm = *(*a+1) ;//得到&L的地址
printf( "%f\n", mm(3.14));getchar();
return 0;
}
最后看一个比较难点的例子:double ( *(* (*fp3)( double(*u)(double k) ) )[1] )( double k );
对比:double (* (* P1) [1] )( double (*p) ( double k ) );
/*分析 double (* (* P1)[1] )( double (*p) ( double k ) ) :用左右法分析 :首先找到未知变量P1,往右看到第一个括号,往左看遇到第一个*,说明P1是一个指针。跳出第一个内部括号,首先与【】结合,因为【】优先级比*高,说明P1是一个数组指针。在往右看是第二个括号),然后往左看遇到第一个*,说明数组指针里面的元素是一个指针,什么类型的指针呢?跳出第二个括号,往右是参数列表,说明数组中包含的是函数指针,这些函数double (*p) ( double k )类型,返回值类型是double */
使用typedef分解 double (* (* P1)[1] )( double (*p) ( double k ) );
第一步:typedef double ( * ppt )( double k );==> double (* (* P1)[10] )( ppt k );
第二部:typedef ppt (*p)[1];==> 此时如果定义一个变量 (p a;),那么a的类型将和P1的类型一致
使用typedef分解 double ( * (* (*fp3)( double(*u)(double k) ) ) [1] )( double k );
/* 如果把 (*fp3)( double(*u)(double k) ) 替换成P1,那么将和上面举的例子相同 */
第一步:typedef p (*fp3)( ppt point );//返回类型是一个数组指针,所以p是一个数组指针类型
第二步:typedef ppt (*p)[1];//定义一个数组指针,数组指针所指向的数组具有“函数指针,指向形参为double,返回为double”的特征
第三步:typedef double ( * ppt )( double k );//定义一个函数指针,指向形参为double,返回为double的函数
贴上测试类型代码:
#include <stdio.h>
typedef double ( * ppt )( double k );
typedef ppt (*p)[1];//p的类型为 ppt (*)[1];
typedef p (*fp)( ppt point );//定义一个函数指针,参数也是一个函数指针typedef double ( *(* (*fp3)( double(*u)(double k) ) )[1] )( double k );
int main ()
{
fp3 jj;
fp qq;
jj = qq;return 0;
}//没有报错,说明使用typedef分解正确
最后贴上使用实例,以帮助大家更详细的了解:
#include <stdio.h>
typedef double ( * ppt )( double k );
typedef ppt (*p)[1];//p的类型为 ppt (*)[1];
typedef p (*fp)( ppt point );//定义一个函数指针,参数也是一个函数指针//跟前面一样,先找到变量名fp3(这里fp3其实是新类型名),往右看是圆括号,调转方向往左是*,说明fp3是一个指针;跳出圆括号,
//往右看是ppt类型的参数,说明fp3是一个函数指针,接着往左是*号,说明该函数的返回值是一个指针;跳出第二层圆括号,往右是[]运算符,
//说明函数的返回值是一个数组指针,接着往左是*号,说明数组中包含的是指针;跳出第三层圆括号,往右是参数列表,说明数组中包含的
//是函数指针,这些函数有一个double的形参,返回值类型是double。简言之,fp3是一个指向函数的指针,所指向的函数具有ppt类型参数返回double类型的值,
//且返回一个含有1个数组指针,并且该数组指针所指向的数组具有ppt类型并且步长一样的数组。
typedef double ( *(* (*fp3)( double(*u)(double k) ) )[1] )( double k );//typedef double *(*P2[10])();//指针数组,数组里面的元素是函数指针,指向没有参数返回值为double类型的函数
//typedef double (* (* P1)[10])();//数组指针,第一个*说明数组中包含的是指针,往右是参数列表,说明数组中包含的是函数指针,这些函数没有参数,返回值类型是double
/* 如果max函数的类型定义为 P2,则会报错,因为函数不允许反回数组
P1 max( int *k )
{
P1 pt;
return 0;
}*/double test( double result )
{
return result;
}/* 参数point为指向ppt(返回值为double,参数为double类型的参数)类型的指针 */
p func( ppt point )
{
ppt b[1] = { point } ;//创建一个ppt类型的数组,数组元素为ppt类型
p point_b;//创建一个数组指针,用于指向ppt类型的数组,注意步长要一样
point_b = &b;
return point_b;
}int main ()
{
// ppt本身就是函数指针,ppt*为指向函数指针的指针
// ppt* point;
// point = &test;//报错fp a;//定义一个fp类型的函数指针
ppt point_test;//定义一个ppt类型的函数指针a = &func;//&操作符只是显示地说明了编译器隐式执行的任务,a = func也可以
point_test = **a( &test );//*a( &test ),取得数组b的地址。**a( &test ),取得数组b里面的内容,即test的地址printf( "%f\n", point_test(3.14));
getchar();}
参考链接:
https://www.cnblogs.com/Lunais/p/5969181.html
https://blog.youkuaiyun.com/skywalker_leo/article/details/48622193