您的位置:首页 > 编程语言 > C语言/C++

c语言之左右法则

2016-11-22 16:00 696 查看
曾经碰到过让你迷惑不解、类似于int * (* (*fp1) (int) ) [10];这样的变量声明吗?本文将由易到难,一步一步教会你如何理解这种复杂的

C/C++声明:我们将从每天都能碰到的较简单的声明入手,然后逐步加入const修饰符和typedef,还有函数指针,最后介绍一个能够让你准确地 理解任何C/C++声明的“右左法则”。需要强调一下的是,复杂的C/C++声明并不是好的编程风格;我这里仅仅是教你如何去理解这些声明。

基础

让我们从一个非常简单的例子开始,如下:

int n;

这个应该被理解为“declare n as an int”(n是一个int型的变量)。

接下去来看一下指针变量,如下:

int *p;

这个应该被理解为“declare p as an int * ”(p是一个int * 型的变量),或者说p是一个指向一个int型变量的指针。我想在这里展开讨论一下:我觉得在声明一个指针(或引用)类型的变量时,最好将*(或&)写在紧靠变量之前,而不是紧跟基本类型之后。这样可以避免一些理解

上的误区,比如:

int* p,q;

第一眼看去,好像是p和q都是int*类型的,但事实上,只有p是一个指针,而q是一个最简单的int型变量。

我们还是继续我们前面的话题,再来看一个指针的指针的例子:

char **argv;

理论上,对于指针的级数没有限制,你可以定义一个浮点类型变量的指针的指针的指针的指针…

再来看如下的声明:

int RollNum[30][4];

int (*p)[4]=RollNum;

int *q[5];

这里,p被声明为一个指向一个4元素(int类型)数组的指针,而q被声明为一个包含5个元素(int类型的指针)的数组。

另外,我们还可以在同一个声明中混合实用*和&,如下:

int **p1; // p1 is a pointer to a pointer to an int.

int *&p2; // p2 is a reference to a pointer to an int.

int &*p3; // ERROR: Pointer to a reference is illegal.

int &&p4; // ERROR: Reference to a reference is illegal.

注:p1是一个int类型的指针的指针;p2是一个int类型的指针的引用;p3是一个int类型引用的指针(不合法!);p4是一个int类型引用的引 用(不合法!)。

函数指针

函数指针可能是最容易引起理解上的困惑的声明。函数指针在DOS时代写TSR程序时用得最多;在Win32和X-Windows时代,他们被用在需要回调 函数的场合。当然,还有其它很多地方需要用到函数指针:虚函数表,STL中的一些模板,Win NT/2K/XP系统服务等。让我们来看一个函数指针的简单例子:

int (*p)(char);

这里p被声明为一个函数指针,这个函数带一个char类型的参数,并且有一个int类型的返回值。另外,带有两个float类型参数、返回值是char类型的指针的指针的函数指针可以声明如下:

char ** (*p)(float, float);

那么,带两个char类型的const指针参数、无返回值的函数指针又该如何声明呢?参考如下:

void * (* a[5])(char * const, char * const);

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; 整形变量

2.int *a; 整形指针变量

3.int **a; 整形指针的指针变量(一个指向指针的指针,它指向的指针指向一个整形数)

4.int a[10]; 整形数组

5.int *a[10]; 整形指针数组(一个数组中有10个指针,该指针指向一个整形数)

6.int (*a)[10]; 整形数组指针(一个指向有10个整形数组的指针)

7.int (*a)(int); 函数指针变量(一个指向函数的指针,该函数有一个整形参数并返回一个整形数)

8.int (*a[10])(int); 函数指针数组(一个有10个指针的数组,该指针指向一个函数,该函数有一个整形参数并返回一个整形数)

下面结合例子来演示一下“右左法则”的使用。

int * (* (*fp1) (int) ) [10];

阅读步骤:

1. 从变量名开始 ——————————————– fp1

2. 往右看,什么也没有,碰到了),因此往左看,碰到一个* —— 一个指针

3. 跳出括号,碰到了(int) ———————————– 一个带一个int参数的函数

4. 向左看,发现一个* ————————————— (函数)返回一个指针

5. 跳出括号,向右看,碰到[10] —————————— 一个10元素的数组

6. 向左看,发现一个* ————————————— 指针

7. 向左看,发现int —————————————– int类型

总结:fp1被声明成为一个函数的指针,该函数返回指向指针数组的指针.

再来看下面的一些例子:

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

总结: arr是一个函数指针数组,该数组里的元素指向一个形参为空,返回值是一个函数指针,该指针指向一个形参为空,返回值为int*。

float ( * ( *b()) [] )();

总结: b是一个函数,该函数形参为空,返回值是一个数组指针,该指针指向一个函数指针数组,数组的元素指向一个形参为空,返回值为float的函数。

void * ( * c) ( char a, int (*b)());

总结: c是一个函数指针变量,指向一个有两个参数的函数,该函数返回值为void * 类型,第一个参数为char,第二个形参为函数指针,指针指向一个形参为空,返回值为int * 的函数。

float ( * ( * e[10]) (int *) ) [5];

总结:e是一个函数指针数组数组里的元素指向一个形参为int * ,返回值是一个数组指针,指向的数组为float型的数组。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  c语言