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 ...
随机推荐
- Easy Climb
题意: 有n块石头,给定他们的高度,现保持第一和最后一块高度不变,其他可增加和减少高度,求通过变换使所有相邻石头的高度差的绝对值不大于d,所变化高度总和的最小值. 分析: 状态还可以想出来,dp[i] ...
- 【SQL server】安装和配置
(1)SQL sever 版本问题1: SQL sever 2000 .SQL sever 2005.SQL sever 2008 .SQL sever 2008 R2 安装的时候需要注意是SQL s ...
- 全栈工程师眼中的HTTP
HTTP,是Web工程师每天打交道最多的一个基本协议.很多工作流程.性能优化都围绕HTTP协议来进行,但是我们对HTTP的理解是否全面呢?如果前端工程师和后台工程师坐在一起玩捉鬼游戏,他们对HTTP的 ...
- linux 常用命令基础
linux常用的命令 shell 是命令语句,命令解释程序以及程序设计语言的统称,它不仅仅拥有自己内建的shell命令集,同时也能被系统中其他应用程序所调用 shell 的一个重要特性是它本身就是一个 ...
- LeetCode题解——Longest Common Prefix
题目: 给定一系列的字符串,找出这些字符串的最长公共前缀. 解法: 暴力法,依次比较每个字符串的每个字符,碰到第一个不同的就返回之前找到的前缀. 代码: class Solution { public ...
- 数往知来C#面向对象准备〈二〉
面向对象(OOP→Object-Oriented Programming) 1.什么是面向对象? 一种分析问题的方式. 2.面向对象三大特征: 封装(隐蔽代码实现/复用/修改方便).继承.多态. 3. ...
- Tkinter教程之Pack篇
本文转载自:http://blog.csdn.net/jcodeer/article/details/1813077 '''Tkinter教程之Pack篇'''#Pack为一布局管理器,可将它视为一个 ...
- 举例详细说明javascript作用域、闭包原理以及性能问题(转)
转自:http://www.cnblogs.com/mrsunny/archive/2011/11/03/2233978.html 这可能是每一个jser都曾经为之头疼的却又非常经典的问题,关系到内存 ...
- Web开发人员需知的Web缓存知识
最近的译文距今已有4年之久,原文有一定的更新.今天踩着前辈们的肩膀,再次把这篇文章翻译整理下.一来让自己对web缓存的理解更深刻些,二来让大家注意力稍稍转移下,不要整天HTML5, 面试题啊叨啊叨的~ ...
- linux 下终端复用软件推荐——tmux
使用过些linux终端,比如Tilda.Terminator. 之前最经常用的是Terminator,其可以上下左右分屏,比较方便,但其有个缺点是经常无故崩溃. 后来遇到Tmux,根据网上的设置配置了 ...