复杂指针

本文详细解析了C语言中复杂指针的定义与使用,包括函数指针、数组指针及多级指针,并通过实例说明如何运用右左法则进行解析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

笔试是会遇到一些复杂指针,如:

13、定义一个函数指针,指向的函数有两个int形参并且返回一个函数指针,返回的指针指向一个有一个int形参且返回int的函数?
A、int (*(*F)(int, int))(int)
B、int (*F)(int, int)
C、int (*(*F)(int, int))
D、*(*F)(int, int)(int)

 

14、声明一个指向含有10个元素的数组的指针,其中每个元素是一个函数指针,该函数的返回值是int,参数是int*,正确的是()
A、(int *p[10])(int*);
B、int [10]*p(int *);
C、int (*(*p)[10])(int *);
D、int ((int *)[10])*p;
E、以上选项都不正确

这里介绍两篇讲解得不错的博客:


常见复杂指针声明的解析

  原文地址:http://blog.youkuaiyun.com/lizhiguo0532/article/details/5778908

  声明:1. 文章如有不妥的地方,请您指正,谢谢.

          2.另外文中有些细节可能引用您的内容却未给出参考,请原谅我的疏忽,你的共享我不会忘记.

          3. Email:lizhiguo0532@163.com  李枝果/lizgo
          4. 转载请保留该部分信息

       

 

//两个原则
//右左法则:首先从最里面的圆括号看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。
//坚持使用typedef来进行类型重定义,不确定优先级的地方可以多加括号。

1. int *p[N];
//这个就是int型指针数组,即N个int型指针所组成的数组
2. int (*p)[N];
//首先p是一个指针,基类型是具有N个int元素的数组,即数组指针
3. int (*p[M])[N];或者int (*(p[M]))[N];
//这是一个数组指针数组,怎么看呢?先看括号内的,*p[M],很显然这是一个数组(优先级[]高于*),什么数组呢?具有M个指针变量的数组。括号内的类型是指针,着我们知道了,跳出括号,int (指针)[N],
//是不是很眼熟?看2的形式,所以里面的指针不是一般的指针,而是具有N个整型数据的数组指针。
//如果现在我们要定义一个数组指针数组来访问二维数组a[5][4],该怎么定义呢?
//我们就和解析的过程反着来定义就可以了,看到这个名字,“数组指针数组”,从左往右看,先看到数组指针,那我们就先来定义数组指针,注意,将来是要访问a[5][4]的(a是一个具有5个元素的数组,这5个元
//素每个都是具有4个int数据的一维数组),将来我们的数组指针就是要指向这个一维数组的
//数组指针定义:int (*p)[4];  再来定义指针数组,在这里前面的数据类型本来就已经是指针(数组指针)了,所以在 *pa[M]里就没必要加*了,可以直接定义成int (*p[M])[N];
//如果我利用typedef就简单明了多了:
//可以参考的形式有:
//a.    
    typedef  int (*A)[N];
    typedef  A  (B[M]);

    B   b;//等价于int (*(b[M]))[N];比较局限
//b.
    typedef  int (*A)[N];
    typedef  A  (B);

    B   b[M];//等价于int (*(b[M]))[N];
//c.
    typedef  int      (A)[N];
    typedef  A    *(B[M]);

    B   b;//等价于int (*(b[M]))[N];比较局限
//d.
    typedef  int      (A)[N];
    typedef  A      *(B);

    B   b[M];//等价于int (*(b[M]))[N];
//e.
    typedef  int (*(A))[N];
    A   b[M];
//f.
    typedef  int      A[N];
    A   *b[M];
//上面的声明中,()在有的地方是可以不加的
4. int (*func)(int *p);
//这是一个基本的函数指针定义方法,无法分解。(这里说明的是:函数名内容也是地址)

5. int (*func)(int *p, int (*f)(int*)); 
//用typedef分解:
     typedef int (*FUNC)(int *);
     int (*func)(int *p,FUNC f);
//典型的例子
     typedef void (*sighandler_t)(int);
     sighandler_t signal(int signum, sighandler_t handler);
//展开如下:
    void     (* signal(int signum, void (* handler)(int)))(int );

6. int (*func[5])(int *p);
// 这是一个函数指针数组,总的来说func是个数组,什么样的数组呢?原来里面的数组元素都是一个个函数指针。可以这样分解
     typedef int (* FUNC)(int *p);
     FUNC   func[5];
//func这个数组的元素的类型是参数维int *,返回值为int 的函数指针

7. int (*(*func)[5])(int *p);
//这是一个函数指针数组指针,注意读法,前面六个字函数指针数组是修饰最后的指针,所以总提来说func是一个指针,什么样的指针呢?
//指向具有5个元素的数组,那这个数组的元素是什么类型呢?哦,原来是函数指针类型,什么类型的函数指针呢?参数int *,返回值 int。
//用typedef分解
    typedef int (* (A))(int *p);
    typedef A   (B)[5];
    typedef B    *M
    M    func;
    //或者
    B   *func;

8. int (*(*func)(int *p))[5]; 
//乍一看,我也看不出来它什么类型,不过可以分解嘛
    typedef  int (*(A))[5];//A是函数指针类型
    A  (* func)(int *p);
    //这下该看出来是什么类型来吧,func是个函数指针,它参数很简单 int *,复杂就复杂在返回值,返回值的类型是A,A的类型就是一个数组指针,
    //而且这个数组指针指向的是具有5个int数据的数组。


总结:
1.如果我们是去读别人的已经声明好的复杂类型,那么我们可以这样,用typedef来将其分解,分解的原则是:
    从最外层的开始用typedef来定义,然后用定义好的类型再去一层一层得定义内部,知道遇见了被定义的标示符为止
2.如果我们知道需要声明一个什么东西了,比如前面的 “函数指针数组指针”,我们这样来声明:从左往右看,找到第一个修饰词“函数指针”,我们就定义一个函数指针
    接下来遇到来“数组”,我们再用定义好的函数指针类型来定义一个数组。最后,我们在这个数组的类型上再定义一个指针就 可以了。



右左法则----复杂指针解析

原文地址:http://blog.sina.com.cn/s/blog_6461040f0100guwn.html

 

因为C语言所有复杂的指针声明,都是由各种声明嵌套构成的。如何解读复杂指针声明呢?右左法则是一个既著名又常用的方法。不过,右左法

则其实并不是C标准里面的内容,它是从C标准的声明规定中归纳出来的方法。C标准的声明规则,是用来解决如何创建声明的,而右左法则是用

来解决如何辩识一个声明的,两者可以说是相反的。右左法则的英文原文是这样说的:

The right-left rule: Start reading the declaration from the innermost parentheses, go right, and then go left. When you

 encounter parentheses, the direction should be reversed. Once everything in the parentheses has been

parsed, jump out of it. Continue till the whole declaration has been parsed.


这段英文的翻译如下:

    右左法则:首先从最里面的圆括号看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。

笔者要对这个法则进行一个小小的修正,应该是从未定义的标识符开始阅读,而不是从括号读起,之所以是未定义的标识符,是因为一个声明里面可能有多个标识符,但未定义的标识符只会有一个。

现在通过一些例子来讨论右左法则的应用,先从最简单的开始,逐步加深:

int (*func)(int *p);

首先找到那个未定义的标识符,就是func,它的外面有一对圆括号,而且左边是一个*号,这说明func是一个指针,然后跳出这个圆括号,先看

右边,也是一个圆括号,这说明(*func)是一个函数,而func是一个指向这类函数的指针,就是一个函数指针,这类函数具有int*类型的形参,返回值类型是 int。

int (*func)(int *p, int (*f)(int*));

func被一对括号包含,且左边有一个*号,说明func是一个指针,跳出括号,右边也有个括号,那么func是一个指向函数的指针,这类函数具有int *和int (*)(int*)这样的形参,返回值为int类型。再来看一看func的形参int (*f)(int*),类似前面的解释,f也是一个函数指针,指向的函数具有int*类型的形参,返回值为int。

int (*func[5])(int *p);

func右边是一个[]运算符,说明func是一个具有5个元素的数组,func的左边有一个*,说明func的元素是指针,要注意这里的*不是修饰 func的,而是修饰func[5]的,原因是[]运算符优先级比*高,func先跟[]结合,因此*修饰的是func[5]。跳出这个括号,看右边,也是一对圆括号,说明func数组的元素是函数类型的指针,它所指向的函数具有int*类型的形参,返回值类型为int。
int (*(*func)[5])(int *p);

func被一个圆括号包含,左边又有一个*,那么func是一个指针,跳出括号,右边是一个[]运算符号,说明func是一个指向数组的指针,现在往左看,左边有一个*号,说明这个数组的元素是指针,再跳出括号,右边又有一个括号,说明这个数组的元素是指向函数的指针。总结一下,就是:func是一个指向数组的指针,这个数组的元素是函数指针,这些指针指向具有int*形参,返回值为int类型的函数。

int (*(*func)(int *p))[5];

func是一个函数指针,这类函数具有int*类型的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素的数组。

要注意有些复杂指针声明是非法的,例如:

int func(void) [5];

func是一个返回值为具有5个int元素的数组的函数。但C语言的函数返回值不能为数组,这是因为如果允许函数返回值为数组,那么接收这个数组的内容的东西,也必须是一个数组,但C语言的数组名是一个右值,它不能作为左值来接收另一个数组,因此函数返回值不能为数组。

int func[5](void);

func是一个具有5个元素的数组,这个数组的元素都是函数。这也是非法的,因为数组的元素除了类型必须一样外,每个元素所占用的内存空间也必须相同,显然函数是无法达到这个要求的,即使函数的类型一样,但函数所占用的空间通常是不相同的。

作为练习,下面列几个复杂指针声明给读者自己来解析。

int (*(*func)[5][6])[7][8];

int (*(*(*func)(int *))[5])(int *);

int (*(*func[7][8][9])(int*))[5];

        实际当中,需要声明一个复杂指针时,如果把整个声明写成上面所示的形式,对程序可读性是一大损害。应该用typedef来对声明逐层

分解,增强可读性,例如对于声明:

int (*(*func)(int *p))[5];

可以这样分解:

typedef  int (*PARA)[5];
typedef PARA (*func)(int *);

这样就容易看得多了。 
  

答案,同时给出用typedef的分解方法:

int (*(*func)[5][6])[7][8];

func是一个指向数组的指针,这类数组的元素是一个具有5X6个int元素的二维数组,而这个二维数组的元素又是一个二维数组。

typedef int (*PARA)[7][8];
typedef PARA (*func)[5][6];


int (*(*(*func)(int *))[5])(int *);

func是一个函数指针,这类函数的返回值是一个指向数组的指针,所指向数组的元素也是函数指针,指向的函数具有int*形参,返回值为int。

typedef int (*PARA1)(int*);
typedef PARA1 (*PARA2)[5];
typedef PARA2 (*func)(int*);

int (*(*func[7][8][9])(int*))[5];

func是一个数组,这个数组的元素是函数指针,这类函数具有int*的形参,返回值是指向数组的指针,所指向的数组的元素是具有5个int元素

的数组。

typedef int (*PARA1)[5];
typedef PARA1 (*PARA2)(int*);
typedef PARA2 func[7][8][9];


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值