char (*(*p[3])( int ))[5] 等等一系列 左右法则
看这个:
C指针声明解读之左右法则
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.
这段英文的翻译如下:
右左法则:首先从最里面的圆括号内未定义的标识符开始阅读看起,然后往右看,再往左看。每当遇到圆括号时,就应该掉转阅读方向。一旦解析完圆括号里面所有的东西,就跳出圆括号。重复这个过程直到整个声明解析完毕。
总之对声明进行分析,最根本的方法还是按优先级和结合性来类比替换,从那些最基本的声明进行类比,简化,从而进行理解。下面分析几个例子,来具体阐述如何使用这种方法。
#1:int* (*a[5])(int, char*);
首先看到标识符名a,"[]"优先级大于"*",a与"[5]"先结合。所以a是一个数组,这个数组有5个元素,每一个元素都是一个指针,指针指向"int* (int, char*)",很明显,指向的是一个函数,这个函数参数是"int, char*",返回值是"int*"。OK,结束了一个。:)
#2:void (*b[10]) (void (*)());
b是一个数组,这个数组有10个元素,每一个元素都是一个指针,指针指向一个函数,函数参数是"void (*)()"【注:这也是一个函数指针, 参数为空,返回为void】,返回值是"void"。完毕!
#3:int(*)() (*c)[9];
c是一个指针,指针指向一个数组,这个数组有9个元素,每一个元素都是"int(*)()"(也即一个函数指针,指向一个函数,这个函数的参数为空,返回值是int型)。
#4:int (*(*d)[5])(int *);
(*d)------指针;
(*d)[5]------这个指针指向一个数组;
*(*d)[5]------这个数组中每个元素都是指针类型;
int (int *)------ 什么类型的指针?这个类型的。
#5:int (*(*e)(int *))[5];
*e-----向右遇到括号,向左遇到*,说明e是个指针,啥指针呢?
(*e)(int *)------跳出括号向右遇到(int *),说明这个指针是个函数指针,形参为int*, 返回值为何?且听下回分解:);
*(*e)(int *)------返回值为何?向右遇到括号,再向左,喔,遇到*了,那就是返回了一个指针了。啥指针呢? 同样地,下回分解;
(*(*e)(int *))[5]-------向右遇到[],说明那是个指向数组的指针,是啥数组呢?不急,慢慢来;
int (*(*e)(int *))[5]-------向左遇到int,喔,明白了,就是个简单的整型数组。OVER
当然实际当中,当需要声明一个复杂指针时,如果把整个声明写成上面所示的形式,对程序可读性将是一个巨大损害。谁要是写出这样BT的指针声明,那就真是丢rp了,估计会被骂死!。
还是用typedef来对声明逐层分解替换下吧,增强可读性。
例如对于上面的声明:int (*(*func)(int *))[5]; 可以这样分解:
typedef int (*pArr)[5];
typedef pArr (*func)(int *);
这样就容易读得多了啊!
再看看这个啥意思? typedef int (* (* (*FUNC)(int *) )[5] )(int *); ---- 晕了吧。
其实typedef int (* (* (*FUNC)(int *) )[5] )(int *);
等价与下面的:)
typedef int (*PF)(int *);
typedef PF (*PARRAY)[5];
typedef PARRAY (*FUNC)(int *);
(*(void (*)())0)();------->这个呢?
按左右法则:
(void (*)()) -----是一个返回值为void,参数为空的函数指针原型。
(void (*)())0-----把0强转成一个返回值为void,参数为空的函数指针,指针指向的地址为0.
*(void (*)())0-----前面加上*表示整个是一个返回值为void的函数的名字
(*(void (*)())0)()------这当然就是一个函数调用了。
再typedef化简下:
typedef void (*pf)();
(*(pf)0)();
char (*(*p[3])( int ))[5] 等等一系列 左右法则的更多相关文章
- char 数组和 int 之间转化
上周工作结束,来到斯凯网络也将近半个月来. 没有新人的感念,最多的是将自己当作一个战士. 废话不多说,直接入正题,在没有仔细考虑问题之前我们总会 觉得:这尼玛的有毛线难度啊,不就是一个 int 转为c ...
- C++ char*,const char*,string,int 的相互转换
C++ char*,const char*,string,int 的相互转换 1. string转const char* string s ="abc";const char* ...
- 34 char类型转换为int类型
#include<iostream> #include<cstdlib > using namespace std; int main() { char a=101; int ...
- int main(int argc,char *argv[])与int main(int argc,char **argv)区别?
int main(int argc,char *argv[])与int main(int argc,char **argv)区别? 这两种是一个等价的写法 而int main(int argc,cha ...
- MySql 时间戳存char还是存int?
一次小事故,让我对时间戳存char还是存int有了深刻的印象. 生产环境的sql条件涉及到时间戳字段的大小比较(between and),当时设计的时间戳类型是char(10),结果当数据量达到200 ...
- error C2556: 'const char &MyString::operator [](int)' : overloaded function differs only by return type from 'char &MyString::operator [](int)'
char & operator[](int i);const char & operator[](int i);/*const char & operator(int i);* ...
- char * const * (*a) (int b)
char * const * (*a) (int b), 按照c++ program language的读法,从右往左读,* 读作pointer to 把(*a) (int b看作整体, (*a) ( ...
- char类型和int类型之间的转换
在视屏课程第二章里,我们已经学习了一些常用的数据类型转换.然而,有一些时候我们会经常会遇到将char类型转换成int类型,或者需要将int类型转换为char类型的情况. 这里,我们来探讨一下这种不常用 ...
- (C语言)char类型与int类型相加
#include <stdio.h> int main(void) { ; ; int c = a + b; a += b; printf("c=%d",c); //p ...
随机推荐
- Metaspace 之一--java8 去掉 perm 用 Metaspace 来替代
正如大家所知,JDK 8 Early Access版已经提供下载.这使开发者可以体验Java8的新特性.其中之一,是Oracle从JDK7发布以来就一直宣称的要完全移除永久代空间.例如,字符串内部池, ...
- Asp.net TextBox常规输入验证
Asp.net TextBox只能输入数字<asp:textbox id="TextBox1" onkeyup="if(isNaN(value))execComma ...
- cocos2d-x 添加背景音乐和音效-SimpleAudioEngine
首先,要想使用音效,需要启用音效引擎库CocosDenshion中的SimpleAudioEngine类, #include "SimpleAudioEngine.h" Cocos ...
- C语言-简单哈希表(hash table)
腾讯三面的时候,叫我写了个哈希表,当时紧张没写好···结果跪了··· 回来后粪发涂墙,赶紧写了一个! 什么都不说了···先让我到厕所里面哭一会··· %>_<% 果然现场发挥,以及基础扎实 ...
- 面向切面编程(AOP)及其作用
在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用. 1.面向切面编程(AOP) 面向切面编程(AOP)就是对软件系统不同关注点的分离,开发者通过拦截方法调用并在方法调用前后添加辅助代码. ...
- dwr消息推送
闲来无事,把自己关于对dwr消息推送的实现过程描述一番. 首先第一步,当然在工程中是加入dwr.jar了,接着在web.xml中配置以下代码 <servlet> <servlet-n ...
- C#相关图书推荐
C#入门经典(第6版) 作 者 [美] Karli Watson,Jacob Vibe Hammer,Jon D Reid 等 著: 出 版 社 清华大学出版社 出版时间 2014-01-0 ...
- bzoj 4423 [AMPPZ2013]Bytehattan(对偶图,并查集)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=4423 [题意] 给定一个平面图,随时删边,并询问删边后两点是否连通.强制在线. [科普 ...
- bzoj 3091 城市旅行(LCT+数学分析)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3091 [思路] 膜Popoqqq大爷的题解 click here [代码]是坑... ...
- UIButton 在 iOS7.0与iOS7.1 中关于enabled的一点区别
前些日子,在一台iOS7.0的设备上进行调试,关于UIButton的一部分代码如下 1 self.btn_loadmore.enabled = NO; 2 [self.btn_loadmore set ...